如何设计一个工作流系统分享

如何设计一个工作流系统分享

工作流的应用场景

基于插件化架构的数据处理流水线,专为高效、灵活的数据分析任务设计。

工作流通过标准化接口将数据采集、数据处理、发布等环节解耦为独立插件,支持动态注册与自由编排,实现从数据输入到结果输出的全流程自动化管理。

请在此添加图片描述

固定工作流

首先演示一个固定工作流如何实现,工作流通过数组顺序存储插件名,前驱插件的输出作为后续插件的输入,形成链式处理管道。

一、项目文件结构

workflow/
├── main.go            # 主程序入口
├── workflows/          # 工作流核心实现
│   ├── data.go        # 数据结构定义
│   ├── collector.go   # 采集插件
│   ├── processor.go   # 数据处理插件
│   └── publisher.go   # 发布插件
└── README.md          # 使用说明

请在此添加图片描述


二、完整代码实现

1. 数据定义 (workflows/data.go)
package workflows

// 数据实体
type Data struct {
	ID         string  // 数据ID
	Value      float64 // 数值字段
	Text       string  // 文本字段
	ProcessType string // 处理类型标识
}

// 处理类型常量
const (
	ProcessClean     = "clean" // 数据清洗
	ProcessTransform = "transform" // 数据转换
	ProcessAnalyze   = "analyze" // 数据分析
)
2. 采集插件 (workflows/collector.go)
package workflows

import "fmt"

// 模拟数据源
var mockData = []Data{
	{ID: "D001", Value: 10.5, Text: " Order #123 ", ProcessType: ProcessClean},
	{ID: "D002", Value: 25.0, Text: "VIP Customer", ProcessType: ProcessTransform},
	{ID: "D003", Value: 99.9, Text: "Urgent!", ProcessType: ProcessAnalyze},
}

// 数据采集插件
func CollectData(outCh chan<- Data) {
	for _, data := range mockData {
		fmt.Printf("[采集] ID:%s 原始值:%.1f\n", data.ID, data.Value)
		outCh <- data
	}
	close(outCh) // 关闭通道表示采集结束
}
3. 数据处理插件 (workflows/processor.go)
package workflow

import (
	"fmt"
	"strings"
)

// 数据处理插件
func ProcessData(inCh <-chan Data, outCh chan<- Data) {
	for data := range inCh {
		fmt.Printf("[处理] 收到数据:%s 类型:%s\n", data.ID, data.ProcessType)
		
		// 根据类型执行不同处理
		switch data.ProcessType {
		case ProcessClean:
			data.Text = strings.TrimSpace(data.Text) // 清洗空格
		case ProcessTransform:
			data.Value = data.Value * 1.5            // 数值转换
		case ProcessAnalyze:
			if data.Value > 50 {
				data.Text = "[高价值]" + data.Text    // 打标签
			}
		}
		
		outCh <- data
	}
	close(outCh)
}
4. 发布插件 (workflows/publisher.go)
package workflow

import "fmt"

// 数据发布插件
func PublishData(inCh <-chan Data) {
	var successCount int
	
	for data := range inCh {
		// 模拟发布到数据库/消息队列
		fmt.Printf("[发布] ID:%s 最终值:%.2f 文本:%s\n", 
			data.ID, data.Value, data.Text)
		successCount++
	}
	
	fmt.Printf("发布完成,成功%d条\n", successCount)
}
5. 主程序 (main.go)

通过通道阻塞和goroutine协作,确保数据按"采集→处理→发布"顺序流动,主goroutine在PublishData处阻塞等待流程完成

package main

import (
	"workflow/workflows"
)

func main() {
	// 初始化带缓冲的通道
	collectCh := make(chan workflow.Data, 3)
	processCh := make(chan workflow.Data, 3)

	// 启动工作流
	go workflows.CollectData(collectCh)      // 采集数据
	go workflows.ProcessData(collectCh, processCh) // 处理数据
	workflows.PublishData(processCh)         // 发布数据
}

三、执行流程说明

1. 流程图 (Mermaid)

请在此添加图片描述

2. 控制台输出示例
[采集] ID:D001 原始值:10.5
[采集] ID:D002 原始值:25.0
[采集] ID:D003 原始值:99.9
[处理] 收到数据:D001 类型:clean
[处理] 收到数据:D002 类型:transform
[发布] ID:D001 最终值:10.50 文本:Order #123
[处理] 收到数据:D003 类型:analyze
[发布] ID:D002 最终值:37.50 文本:VIP Customer
[发布] ID:D003 最终值:99.90 文本:[高价值]Urgent!
发布完成,成功3条

插件可插拔工作流

为了提高工作流的可扩展性,下面演示如何实现一个可插拔的工作流,实现思路。

可插拔工作流的核心实现原理:通过插件注册中心动态管理插件元信息,工作流引擎在执行时根据注册信息动态调用插件服务,每个插件通过标准化的输入输出契约进行数据交互,从而实现无需修改核心代码即可自由插拔各类功能模块。


系统架构图

请在此添加图片描述


项目结构

workflow-engine/
├── main.go                 # 引擎主入口
├── engine/
│   ├── workflow_builder.go   # 工作流创建和管理
│   ├── registry.go          # 插件注册中心
│   ├── executor.go         # 工作流执行器
│   ├── scheduler.go         # 任务调度器
│   └── types.go            # 类型定义
└── config/
    └── workflows/          # 工作流定义
        └── demo.yaml

plugin-services/            # 独立插件服务(不同进程)
├── collector/
│   ├── main.go             # 数据采集服务
│   └── Dockerfile
├── processor1/
│   ├── main.go             # 数据处理服务1
│   └── Dockerfile
├── processor2/
│   ├── main.go             # 数据处理服务2
│   └── Dockerfile
└── publisher/
    ├── main.go             # 数据发布服务
    └── Dockerfile

核心代码实现

1. 类型定义 (engine/types.go)
package engine

// PluginMeta 定义插件的元数据信息,用于注册和描述插件能力
type PluginMeta struct {
    // Name 插件的唯一标识名称(建议使用小写+下划线命名)
    // 示例: "temperature_collector"
    Name        string            `json:"name"`

    // Endpoint 插件服务的HTTP访问地址(必须包含完整路径)
    // 格式: "http://<host>:<port>/<path>"
    // 示例: "http://192.168.1.10:8080/data_collect"
    Endpoint    string            `json:"endpoint"`

    // Type 插件类型分类(必须为以下四种之一)
    //   "collector" - 数据采集型(工作流起点,必须实现流式接口)
    //   "stream_processor" - 流式处理型(逐条数据处理)
    //   "batch_processor" - 批处理型(批量数据处理) 
    //   "publisher" - 数据输出型(工作流终点,建议实现批处理接口)
    Type        string            `json:"type"`

    // InputSchema 定义插件输入数据的结构契约
    // key: 参数名称, value: 数据类型("int"/"float"/"string"/"bool")
    // 示例: {"sensor_id":"string", "value":"float"}
    InputSchema map[string]string `json:"inputSchema"`

    // OutputSchema 定义插件输出数据的结构契约
    // 格式要求与InputSchema相同
    // 示例: {"status":"string", "processed_value":"float"}
    OutputSchema map[string]string `json:"outputSchema"`
}

// Workflow 定义完整的工作流执行流程
type Workflow struct {
    // Name 工作流的业务标识名称
    // 示例: "temperature_processing"
    Name  string   `json:"name"`

    // Steps 按执行顺序排列的插件名称数组
    // 编排规则:
    //   1. 首元素必须是"collector"类型插件
    //   2. 中间可混合"stream_processor"和"batch_processor"
    //   3. 末元素必须是"publisher"类型插件
    // 示例: ["temp_collector", "filter_processor", "avg_calculator", "db_publisher"]
    Steps []string `json:"steps"`
}

// PluginResponse 定义插件执行的标准响应格式
type PluginResponse struct {
    // Data 插件处理后的业务数据
    // 要求:必须符合插件元数据中OutputSchema的定义
    // 示例: {"avg_temp": 25.6, "samples": 100}
    Data  interface{} `json:"data"`

    // Error 错误信息(成功执行时必须为空)
    // 格式要求:
    //   1. 非空字符串表示执行失败
    //   2. 建议格式:"ERROR_TYPE: error description"
    //   示例: "INVALID_INPUT: temperature value out of range"
    Error string      `json:"error,omitempty"` // omitempty表示空值时不输出
	
	const (
		PluginTypeCollector      = "collector"       // 数据采集型插件
		PluginTypeStreamProcessor = "stream_processor" // 流式处理型插件
		PluginTypeBatchProcessor  = "batch_processor"  // 批处理型插件
		PluginTypePublisher      = "publisher"       // 数据发布型插件
	)
}
2. 插件注册中心 (engine/registry.go)
package engine

import (
    "sync"
)

// Registry 插件注册中心,负责插件的生命周期管理和服务发现
// 采用线程安全设计,支持并发注册和查询
type Registry struct {
    // plugins 存储所有已注册插件的元信息
    // key: 插件名称(需保证唯一性)
    // value: 插件元数据(PluginMeta)
    plugins map[string]PluginMeta

    // mu 读写锁,保证并发安全
    // 规则:
    //   - 写操作(注册/注销)使用写锁(Lock/Unlock)
    //   - 读操作(查询)使用读锁(RLock/RUnlock)
    mu      sync.RWMutex
}

// NewRegistry 创建并初始化一个新的插件注册中心实例
// 返回:
//   *Registry: 初始化后的注册中心指针,插件列表为空
func NewRegistry() *Registry {
    return &Registry{
        plugins: make(map[string]PluginMeta), // 初始化空的插件映射
    }
}

// Register 注册一个新插件(线程安全)
// 参数:
//   meta: PluginMeta 包含插件元信息
// 返回值:
//   error: 注册成功返回nil,插件已存在返回ErrPluginExists
// 注意:
//   - 会覆盖同名的旧插件(根据业务需求可调整)
//   - 调用方应确保meta.Endpoint可访问
func (r *Registry) Register(meta PluginMeta) error {
    r.mu.Lock()         // 获取写锁
    defer r.mu.Unlock() // 确保锁释放
    
    // 检查插件是否已存在
    if _, exists := r.plugins[meta.Name]; exists {
        return ErrPluginExists // 返回预定义的错误
    }
    
    // 注册插件到内存映射
    r.plugins[meta.Name] = meta
    return nil
}

// GetPlugin 根据插件名称查询插件信息(线程安全)
// 参数:
//   name: string 插件名称
// 返回值:
//   PluginMeta: 插件元数据(未找到时返回空结构体)
//   bool: 是否存在(true表示存在)
func (r *Registry) GetPlugin(name string) (PluginMeta, bool) {
    r.mu.RLock()         // 获取读锁
    defer r.mu.RUnlock() // 确保锁释放
    
    meta, exists := r.plugins[name]
    return meta, exists
}

// GetPluginsByType 根据插件类型筛选插件(线程安全)
// 参数:
//   pluginType: string 插件类型 
//     可选值: "collector"/"stream_processor"/"batch_processor"/"publisher"
// 返回值:
//   []PluginMeta: 匹配类型的插件数组(可能为空数组)
// 性能提示:
//   - 频繁调用时可考虑增加缓存优化
func (r *Registry) GetPluginsByType(pluginType string) []PluginMeta {
    r.mu.RLock()         // 获取读锁
    defer r.mu.RUnlock() // 确保锁释放
    
    var result []PluginMeta
    // 遍历所有插件进行筛选
    for _, meta := range r.plugins {
        if meta.Type == pluginType {
            result = append(result, meta)
        }
    }
    return result
}
3. 工作流执行器 (engine/executor.go)
package engine

import (
	"bytes"
	"encoding/json"
	"fmt"
	"net/http"
	"reflect"
	"time"
)

// 执行模式常量
const (
	ExecutionModeStream = "stream"  // 流式处理(逐条)
	ExecutionModeBatch  = "batch"   // 批处理(批量)
)

// ExecutePlugin 执行插件(自动选择模式)
func ExecutePlugin(meta PluginMeta, input interface{}) (interface{}, error) {
	// 根据插件类型动态选择执行模式
	switch meta.Type {
	case PluginTypeBatchProcessor:
		return executeBatchMode(meta, input)  // 批处理模式
	default:
		return executeStreamMode(meta, input) // 默认流式模式(含采集器/发布器)
	}
}

// 流式处理(实时逐条)
func executeStreamMode(meta PluginMeta, input interface{}) (interface{}, error) {
	reqBody, _ := json.Marshal(map[string]interface{}{"data": input})
	
	client := &http.Client{Timeout: 5 * time.Second} // 短超时确保实时性
	resp, err := client.Post(meta.Endpoint, "application/json", bytes.NewReader(reqBody))
	if err != nil {
		return nil, &PluginError{
			PluginName: meta.Name,
			Message:    "流式请求失败: " + err.Error(),
			Mode:       ExecutionModeStream,
		}
	}
	defer resp.Body.Close()

	var result PluginResponse
	if err := json.NewDecoder(resp.Body).Decode(&result); err != nil {
		return nil, &PluginError{
			PluginName: meta.Name,
			Message:    "流式响应解析失败: " + err.Error(),
			Mode:       ExecutionModeStream,
		}
	}
	
	if result.Error != "" {
		return nil, &PluginError{
			PluginName: meta.Name,
			Message:    "流式处理错误: " + result.Error,
			Mode:       ExecutionModeStream,
		}
	}
	
	return result.Data, nil
}

// 批处理(批量高效)
func executeBatchMode(meta PluginMeta, input interface{}) (interface{}, error) {
	batchInput := map[string]interface{}{"batch": toBatchSlice(input)}
	reqBody, _ := json.Marshal(batchInput)
	
	client := &http.Client{Timeout: 30 * time.Second} // 长超时适应大数据量
	resp, err := client.Post(meta.Endpoint, "application/batch", bytes.NewReader(reqBody))
	if err != nil {
		return nil, &PluginError{
			PluginName: meta.Name,
			Message:    "批处理请求失败: " + err.Error(),
			Mode:       ExecutionModeBatch,
		}
	}
	defer resp.Body.Close()

	var result struct {
		Batch []interface{} `json:"batch"` // 批处理专用响应格式
		Error string        `json:"error"`
	}
	if err := json.NewDecoder(resp.Body).Decode(&result); err != nil {
		return nil, &PluginError{
			PluginName: meta.Name,
			Message:    "批处理响应解析失败: " + err.Error(),
			Mode:       ExecutionModeBatch,
		}
	}
	
	if result.Error != "" {
		return nil, &PluginError{
			PluginName: meta.Name,
			Message:    "批处理执行错误: " + result.Error,
			Mode:       ExecutionModeBatch,
		}
	}
	
	return result.Batch, nil
}

// 数据标准化转换(兼容单条/数组)
func toBatchSlice(input interface{}) []interface{} {
	if arr, ok := input.([]interface{}); ok {
		return arr
	}
	
	val := reflect.ValueOf(input)
	if val.Kind() == reflect.Slice {
		result := make([]interface{}, val.Len())
		for i := 0; i < val.Len(); i++ {
			result[i] = val.Index(i).Interface()
		}
		return result
	}
	
	return []interface{}{input} // 单条数据自动包装
}
4. 工作流构建器 (workflow-engine)
package engine

import (
	"errors"
)

// WorkflowBuilder 工作流构建器(线程安全)
type WorkflowBuilder struct {
	reg *Registry
	mu  sync.RWMutex
}

// NewWorkflowBuilder 创建构建器实例
func NewWorkflowBuilder(reg *Registry) *WorkflowBuilder {
	return &WorkflowBuilder{
		reg: reg,
	}
}

// CreateWorkflow 创建新工作流(基础版)
// 参数:
//   name: 工作流名称
//   steps: 插件执行顺序
// 返回值:
//   *Workflow: 创建的工作流实例
//   error: 当插件不存在或流程不合法时返回错误
func (wb *WorkflowBuilder) CreateWorkflow(name string, steps []string) (*Workflow, error) {
	wb.mu.Lock()
	defer wb.mu.Unlock()

	// 校验工作流基础规则
	if len(steps) == 0 {
		return nil, errors.New("工作流必须包含至少一个步骤")
	}

	// 校验首节点是否为collector类型
	if first, exists := wb.reg.GetPlugin(steps[0]); !exists || first.Type != PluginTypeCollector {
		return nil, errors.New("工作流必须以collector插件开始")
	}

	// 校验末节点是否为publisher类型
	if last, exists := wb.reg.GetPlugin(steps[len(steps)-1]); !exists || last.Type != PluginTypePublisher {
		return nil, errors.New("工作流必须以publisher插件结束")
	}

	// 校验中间节点类型
	for i := 1; i < len(steps)-1; i++ {
		meta, exists := wb.reg.GetPlugin(steps[i])
		if !exists {
			return nil, fmt.Errorf("插件未注册: %s", steps[i])
		}
		if meta.Type != PluginTypeStreamProcessor && meta.Type != PluginTypeBatchProcessor {
			return nil, fmt.Errorf("中间节点必须是processor类型: %s", steps[i])
		}
	}

	return &Workflow{
		Name:  name,
		Steps: steps,
	}, nil
}

// CreateWorkflowFromConfig 从配置文件创建工作流
func (wb *WorkflowBuilder) CreateWorkflowFromConfig(configPath string) (*Workflow, error) {
	data, err := os.ReadFile(configPath)
	if err != nil {
		return nil, err
	}

	var config struct {
		Name  string   `json:"name"`
		Steps []string `json:"steps"`
	}
	if err := json.Unmarshal(data, &config); err != nil {
		return nil, err
	}

	return wb.CreateWorkflow(config.Name, config.Steps)
}

// ValidateWorkflow 校验工作流合法性
func (wb *WorkflowBuilder) ValidateWorkflow(flow *Workflow) error {
	_, err := wb.CreateWorkflow(flow.Name,package main

import (
	"workflow-engine/engine"
	"encoding/json"
	"fmt"
	"net/http"
	"log"
	
	"github.com/gorilla/mux"
)

func main() {
	// 初始化注册中心
	reg := engine.NewRegistry()
	
	// 预注插件集(每个类型各一个)
	preRegisterPlugins(reg)
	
	// 创建路由
	r := mux.NewRouter()
	
	// 插件注册接口
	r.HandleFunc("/register", func(w http.ResponseWriter, r *http.Request) {
		var meta engine.PluginMeta
		if err := json.NewDecoder(r.Body).Decode(&meta); err != nil {
			http.Error(w, "Invalid request body", http.StatusBadRequest)
			return
		}
		
		if err := reg.Register(meta); err != nil {
			http.Error(w, err.Error(), http.StatusConflict)
			return
		}
		
		w.WriteHeader(http.StatusCreated)
		json.NewEncoder(w).Encode(map[string]string{"status": "registered"})
	}).Methods("POST")
	
	// 工作流执行接口
	r.HandleFunc("/execute/{workflow}", func(w http.ResponseWriter, r *http.Request) {
		vars := mux.Vars(r)
		workflowName := vars["workflow"]
		
		// 根据工作流名称选择预定义工作流
		flow, err := getPredefinedWorkflow(workflowName)
		if err != nil {
			http.Error(w, err.Error(), http.StatusNotFound)
			return
		}
		
		// 执行工作流
		result, err := engine.ExecuteWorkflow(flow, reg, nil)
		if err != nil {
			http.Error(w, err.Error(), http.StatusInternalServerError)
			return
		}
		
		json.NewEncoder(w).Encode(map[string]interface{}{
			"workflow": workflowName,
			"status":   "completed",
			"result":   result,
		})
	}).Methods("POST")
	
	// 启动服务
	log.Println("Workflow engine started on :8080")
	log.Fatal(http.ListenAndServe(":8080", r))
}

//插件注册函数
func preRegisterPlugins(reg *engine.Registry) {
	// 1. 数据采集器
	reg.Register(engine.PluginMeta{
		Name:     "sensor_collector",
		Endpoint: "http://sensor-collector:8080/collect",
		Type:     engine.PluginTypeCollector,
		InputSchema: map[string]string{
			"sensor_id":  "string", // 传感器ID
			"interval":  "int",    // 采集间隔(ms)
		},
		OutputSchema: map[string]string{
			"sensor_id": "string",  // 传感器ID
			"value":     "float",   // 采集值
			"unit":      "string",  // 单位
			"timestamp": "string",  // 时间戳
		},
	})
	
	// 2. 流式处理器
	reg.Register(engine.PluginMeta{
		Name:     "data_filter",
		Endpoint: "http://data-filter:8081/process",
		Type:     engine.PluginTypeStreamProcessor,
		InputSchema: map[string]string{
			"value":  "float", // 输入值
			"min":    "float", // 最小值
			"max":    "float", // 最大值
		},
		OutputSchema: map[string]string{
			"value":        "float", // 输出值
			"is_filtered": "bool",  // 是否被过滤
		},
	})
	
	// 3. 批量处理器
	reg.Register(engine.PluginMeta{
		Name:     "stats_aggregator",
		Endpoint: "http://stats-aggregator:8082/aggregate",
		Type:     engine.PluginTypeBatchProcessor,
		InputSchema: map[string]string{
			"data":   "[]float64", // 数据集
			"period": "string",    // 统计周期 (hour/day)
		},
		OutputSchema: map[string]string{
			"min":       "float", // 最小值
			"max":       "float", // 最大值
			"average":   "float", // 平均值
			"count":     "int",   // 数据点数
		},
	})
	
	// 4. 数据发布器
	reg.Register(engine.PluginMeta{
		Name:     "db_writer",
		Endpoint: "http://db-writer:8083/write",
		Type:     engine.PluginTypePublisher,
		InputSchema: map[string]string{
			"table": "string",  // 表名
			"data":  "object",  // 数据对象
		},
		OutputSchema: map[string]string{
			"rows_affected": "int",  // 受影响行数
			"status":        "string", // 成功/失败
		},
	})
}

// 工作流存储
var predefinedWorkflows = map[string]engine.Workflow{
	// 实时流式处理工作流
	"realtime_processing": {
		Name: "realtime_processing",
		Steps: []string{
			"sensor_collector", // 数据采集
			"data_filter",       // 流式处理
			"db_writer",         // 数据存储
		},
	},
	
	// 批量分析工作流
	"batch_analysis": {
		Name: "batch_analysis",
		Steps: []string{
			"sensor_collector",  // 数据采集
			"stats_aggregator",  // 批量处理
			"db_writer",         // 数据存储
		},
	},
}

// 获取预定义工作流
func getPredefinedWorkflow(name string) (engine.Workflow, error) {
	if flow, exists := predefinedWorkflows[name]; exists {
		return flow, nil
	}
	return engine.Workflow{}, fmt.Errorf("workflow %s not found", name)
} flow.Steps)
	return err
}
5. 主程序 (main.go)
package main

import (
	"workflow-engine/engine"
	"encoding/json"
	"fmt"
	"net/http"
	"log"
	
	"github.com/gorilla/mux"
)

func main() {
	// 初始化注册中心
	reg := engine.NewRegistry()
	
	// 预注册插件
	preRegisterPlugins(reg)
	
	// 创建路由
	r := mux.NewRouter()
	
	// 插件注册接口
	r.HandleFunc("/register", func(w http.ResponseWriter, r *http.Request) {
		var meta engine.PluginMeta
		if err := json.NewDecoder(r.Body).Decode(&meta); err != nil {
			http.Error(w, "Invalid request body", http.StatusBadRequest)
			return
		}
		
		if err := reg.Register(meta); err != nil {
			http.Error(w, err.Error(), http.StatusConflict)
			return
		}
		
		w.WriteHeader(http.StatusCreated)
		json.NewEncoder(w).Encode(map[string]string{"status": "registered"})
	}).Methods("POST")
	
	// 工作流执行接口
	r.HandleFunc("/execute/{workflow}", func(w http.ResponseWriter, r *http.Request) {
		vars := mux.Vars(r)
		workflowName := vars["workflow"]
		
		// 根据工作流名称选择预定义工作流
		flow, err := getPredefinedWorkflow(workflowName)
		if err != nil {
			http.Error(w, err.Error(), http.StatusNotFound)
			return
		}
		
		// 执行工作流
		result, err := engine.ExecuteWorkflow(flow, reg, nil)
		if err != nil {
			http.Error(w, err.Error(), http.StatusInternalServerError)
			return
		}
		
		json.NewEncoder(w).Encode(map[string]interface{}{
			"workflow": workflowName,
			"status":   "completed",
			"result":   result,
		})
	}).Methods("POST")
	
	// 启动服务
	log.Println("Workflow engine started on :8080")
	log.Fatal(http.ListenAndServe(":8080", r))
}

// 插件注册函数
func preRegisterPlugins(reg *engine.Registry) {
	// 1. 数据采集器
	reg.Register(engine.PluginMeta{
		Name:     "sensor_collector",
		Endpoint: "http://sensor-collector:8080/collect",
		Type:     engine.PluginTypeCollector,
		InputSchema: map[string]string{
			"sensor_id":  "string", // 传感器ID
			"interval":  "int",    // 采集间隔(ms)
		},
		OutputSchema: map[string]string{
			"sensor_id": "string",  // 传感器ID
			"value":     "float",   // 采集值
			"unit":      "string",  // 单位
			"timestamp": "string",  // 时间戳
		},
	})
	
	// 2. 流式处理器
	reg.Register(engine.PluginMeta{
		Name:     "data_filter",
		Endpoint: "http://data-filter:8081/process",
		Type:     engine.PluginTypeStreamProcessor,
		InputSchema: map[string]string{
			"value":  "float", // 输入值
			"min":    "float", // 最小值
			"max":    "float", // 最大值
		},
		OutputSchema: map[string]string{
			"value":        "float", // 输出值
			"is_filtered": "bool",  // 是否被过滤
		},
	})
	
	// 3. 批量处理器
	reg.Register(engine.PluginMeta{
		Name:     "stats_aggregator",
		Endpoint: "http://stats-aggregator:8082/aggregate",
		Type:     engine.PluginTypeBatchProcessor,
		InputSchema: map[string]string{
			"data":   "[]float64", // 数据集
			"period": "string",    // 统计周期 (hour/day)
		},
		OutputSchema: map[string]string{
			"min":       "float", // 最小值
			"max":       "float", // 最大值
			"average":   "float", // 平均值
			"count":     "int",   // 数据点数
		},
	})
	
	// 4. 数据发布器
	reg.Register(engine.PluginMeta{
		Name:     "db_writer",
		Endpoint: "http://db-writer:8083/write",
		Type:     engine.PluginTypePublisher,
		InputSchema: map[string]string{
			"table": "string",  // 表名
			"data":  "object",  // 数据对象
		},
		OutputSchema: map[string]string{
			"rows_affected": "int",  // 受影响行数
			"status":        "string", // 成功/失败
		},
	})
}

// 工作流存储
var predefinedWorkflows = map[string]engine.Workflow{
	// 实时流式处理工作流
	"realtime_processing": {
		Name: "realtime_processing",
		Steps: []string{
			"sensor_collector", // 数据采集
			"data_filter",       // 流式处理
			"db_writer",         // 数据存储
		},
	},
	
	// 批量分析工作流
	"batch_analysis": {
		Name: "batch_analysis",
		Steps: []string{
			"sensor_collector",  // 数据采集
			"stats_aggregator",  // 批量处理
			"db_writer",         // 数据存储
		},
	},
}

// 获取预定义工作流
func getPredefinedWorkflow(name string) (engine.Workflow, error) {
	if flow, exists := predefinedWorkflows[name]; exists {
		return flow, nil
	}
	return engine.Workflow{}, fmt.Errorf("workflow %s not found", name)
}
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包

打赏作者

极客李华

你的鼓励将是我创作的最大动力

¥1 ¥2 ¥4 ¥6 ¥10 ¥20
扫码支付:¥1
获取中
扫码支付

您的余额不足,请更换扫码支付或充值

打赏作者

实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值