Automa架构深度解析:从块连接到工作流执行

Automa架构深度解析:从块连接到工作流执行

【免费下载链接】automa A browser extension for automating your browser by connecting blocks 【免费下载链接】automa 项目地址: https://gitcode.com/gh_mirrors/au/automa

本文深入解析了Automa工作流引擎的核心架构,重点介绍了WorkflowEngine的多工作线程模型、块处理机制、连接映射系统、数据引用与变量系统设计。文章详细阐述了引擎的初始化流程、块执行生命周期、条件处理与分支逻辑、错误处理与容错机制,以及多工作线程间的状态同步和性能优化策略。通过系统化的架构分析,展现了Automa如何高效管理复杂的浏览器自动化工作流。

WorkflowEngine核心引擎架构

Automa的WorkflowEngine是整个自动化流程的核心引擎,负责协调和管理工作流的执行过程。它是一个高度模块化、事件驱动的架构,采用了多工作线程模型来处理复杂的自动化任务。

核心架构组成

WorkflowEngine的架构主要由以下几个核心组件构成:

mermaid

引擎初始化流程

WorkflowEngine的初始化过程是一个精心设计的异步流程,确保所有必要的资源都正确加载和配置:

mermaid

多工作线程模型

WorkflowEngine采用多工作线程(WorkflowWorker)模型来处理并行执行需求。每个工作线程负责执行特定的块序列,并维护自己的执行上下文:

工作线程属性类型描述
idString工作线程唯一标识符
activeTabObject当前活动的浏览器标签信息
currentBlockObject当前正在执行的块
loopListObject循环数据存储
preloadScriptsArray预加载脚本列表

数据引用系统

WorkflowEngine实现了一个强大的数据引用系统,允许块之间共享和传递数据:

// 引用数据结构示例
referenceData: {
  variables: {},        // 用户定义的变量
  table: [],            // 数据表格内容
  secrets: {},          // 安全凭据数据
  loopData: {},         // 循环迭代数据
  workflow: {},         // 工作流元数据
  googleSheets: {},     // Google Sheets数据
  globalData: {}        // 全局共享数据
}

块执行机制

每个块的执行都遵循统一的处理流程:

  1. 模板渲染:使用templating系统处理块中的动态内容
  2. 处理器查找:根据块类型找到对应的处理器函数
  3. 执行包装:使用blockExecutionWrapper处理超时和错误
  4. 结果处理:解析执行结果并确定下一个块
// 块执行包装器示例
function blockExecutionWrapper(blockHandler, blockData) {
  return new Promise((resolve, reject) => {
    let timeout = null;
    const timeoutMs = blockData?.settings?.blockTimeout;
    
    if (timeoutMs && timeoutMs > 0) {
      timeout = setTimeout(() => {
        reject(new Error('Timeout'));
      }, timeoutMs);
    }

    blockHandler()
      .then(resolve)
      .catch(reject)
      .finally(() => {
        if (timeout) clearTimeout(timeout);
      });
  });
}

连接映射系统

WorkflowEngine使用connectionsMap来管理块之间的连接关系,这是一个高效的数据结构:

// 连接映射构建过程
this.connectionsMap = edges.reduce((acc, { sourceHandle, target, targetHandle }) => {
  if (!acc[sourceHandle]) acc[sourceHandle] = new Map();
  acc[sourceHandle].set(target, {
    id: target,
    targetHandle,
    sourceHandle
  });
  return acc;
}, {});

状态管理

WorkflowState组件负责管理所有工作流实例的状态,提供统一的API进行状态操作:

方法参数返回值描述
add(id, data)String, ObjectPromise添加新状态
update(id, data)String, ObjectPromise更新状态
stop(id)StringPromise停止工作流
resume(id, nextBlock)String, ObjectPromise恢复执行

错误处理和恢复机制

WorkflowEngine实现了完善的错误处理机制:

  1. 超时控制:每个块都可以配置独立的超时时间
  2. 异常捕获:使用try-catch包装所有块执行
  3. 状态恢复:支持从断点恢复执行
  4. 日志记录:详细的执行日志用于调试和审计

性能优化特性

引擎包含多个性能优化特性:

  • 数据快照:使用refDataSnapshots进行数据版本控制
  • 连接缓存:预计算和缓存块连接关系
  • 懒加载:按需加载块处理器
  • 内存管理:及时清理不再需要的资源

WorkflowEngine的核心设计理念是提供高度可靠、可扩展的自动化执行环境,通过模块化架构和精心设计的API,确保了Automa能够处理从简单到复杂的各种自动化场景。

块处理机制与连接映射

Automa作为一款基于块连接的可视化浏览器自动化工具,其核心在于高效的块处理机制和精密的连接映射系统。本节将深入解析Automa如何实现块的动态执行、连接管理以及工作流的智能流转。

块处理器的架构设计

Automa采用模块化的块处理器架构,每个功能块都对应一个独立的JavaScript处理器文件。系统通过动态加载机制注册所有可用的块处理器:

const blocksHandler = require.context('./blocksHandler', false, /\.js$/);
const handlers = blocksHandler.keys().reduce((acc, key) => {
  const name = key.replace(/^\.\/handler|\.js/g, '');
  acc[toCamelCase(name)] = blocksHandler(key).default;
  return acc;
}, {});

这种设计使得系统可以轻松扩展新的功能块,只需在blocksHandler目录下添加对应的处理器文件即可。每个处理器都遵循统一的接口规范,返回包含执行结果和下一个块连接信息的数据结构。

连接映射的核心实现

Automa使用connectionsMap数据结构来管理块之间的连接关系,这是一个基于源块输出端口的映射表:

this.connectionsMap = edges.reduce((acc, { sourceHandle, target, targetHandle }) => {
  if (!acc[sourceHandle]) acc[sourceHandle] = new Map();
  acc[sourceHandle].set(target, {
    id: target,
    targetHandle,
    sourceHandle,
  });
  return acc;
}, {});

连接映射的关键特性包括:

特性描述实现方式
多输出支持单个块可以有多个输出端口使用${blockId}-output-${index}格式标识
动态连接查询运行时动态获取下一个执行的块getBlockConnections(blockId, outputIndex)
条件分支支持基于条件的多路径执行条件块返回不同的outputId

块执行的生命周期

每个块的执行都遵循严格的生命周期管理,确保工作流的稳定运行:

mermaid

条件处理与分支逻辑

条件块是连接映射中的关键组件,Automa提供了强大的条件判断机制:

async function conditions({ data, id }, { prevBlockData, refData }) {
  // 条件判断逻辑
  const conditionsResult = await checkConditions(data, conditionPayload);
  
  let outputId = 'fallback';
  if (conditionsResult.match) {
    outputId = data.conditions[conditionsResult.index].id;
  }
  
  return {
    data: resultData,
    nextBlockId: this.getBlockConnections(id, outputId),
  };
}

条件处理支持多种比较类型和重试机制,确保复杂业务逻辑的准确执行。

错误处理与容错机制

Automa实现了完善的错误处理体系,每个块都可以配置自定义的错误处理策略:

const { onError: blockOnError } = replacedBlock.data;
if (blockOnError && blockOnError.enable) {
  if (blockOnError.retry && blockOnError.retryTimes) {
    // 重试逻辑
    await this.executeBlock(replacedBlock, execParam, true);
  }
  
  if (blockOnError.toDo === 'continue') {
    // 继续执行后续块
    executeBlocks(nextBlocks, prevBlockData);
  }
}

错误处理选项包括:

  • 重试机制:配置重试次数和间隔
  • 继续执行:跳过当前块继续流程
  • 回退路径:执行备用的fallback连接
  • 停止工作流:终止整个工作流执行

循环与迭代处理

循环块通过维护循环状态来实现复杂的迭代逻辑:

this.loopList[data.loopId] = {
  index,
  blockId: id,
  id: data.loopId,
  data: currLoopData,
  type: data.loopThrough,
  maxLoop: data.loopThrough === 'numbers' 
    ? data.toNumber + 1 - data.fromNumber 
    : maxLoop,
};

循环处理支持多种数据源:

  • 数字范围迭代
  • 数据表格遍历
  • 自定义数据数组
  • 页面元素集合
  • 变量内容解析

数据传递与上下文管理

块之间的数据传递通过prevBlockDatarefData实现:

const refData = {
  prevBlockData,
  ...this.engine.referenceData,
  activeTabUrl: this.activeTab.url,
};

参考数据包含多个命名空间:

  • variables: 工作流变量
  • table: 数据表格内容
  • loopData: 循环状态数据
  • secrets: 安全凭据信息
  • globalData: 全局共享数据

连接映射的高级特性

Automa的连接映射系统还支持一些高级特性:

并行执行:通过创建多个WorkflowWorker实例实现块的并行执行

this.engine.addWorker({
  state,
  execParam,
  blockId: id,
});

断点调试:支持在执行过程中设置断点进行调试

if (block.data?.$breakpoint && !execParam.resume) {
  this.engine.isInBreakpoint = true;
  this.breakpointState = { block, execParam, isRetry };
}

状态持久化:支持工作流状态的保存和恢复

if (this.workflow.settings.reuseLastState) {
  Object.assign(this.columns, lastState.columns);
  Object.assign(this.referenceData, lastState.referenceData);
}

性能优化策略

为了确保大规模工作流的高效执行,Automa实现了多项性能优化:

  1. 懒加载机制:块处理器按需动态加载
  2. 连接缓存:连接映射在初始化时构建并缓存
  3. 数据快照:引用数据的状态快照管理
  4. 超时控制:每个块可配置独立的执行超时时间
  5. 资源清理:工作流结束时自动清理相关资源

这种精密的块处理机制和连接映射系统使得Automa能够处理复杂的浏览器自动化场景,从简单的表单填写到复杂的数据抓取和工作流编排,都能提供稳定可靠的执行保障。

多工作线程管理与状态同步

Automa作为一个复杂的浏览器自动化扩展,其核心挑战之一是如何高效管理多个并发执行的工作流工作线程,同时确保状态的一致性和同步。在复杂的自动化场景中,单个工作流可能包含数十甚至上百个块,这些块需要并行执行或按特定顺序执行,这就需要一个强大的工作线程管理系统。

工作线程架构设计

Automa采用基于Worker的分布式执行模型,每个工作线程(WorkflowWorker)负责执行特定的块序列。这种设计允许:

  1. 并行执行:多个块可以同时在不同线程中执行
  2. 状态隔离:每个线程拥有独立的状态上下文
  3. 资源优化:根据系统负载动态创建工作线程

mermaid

工作线程生命周期管理

每个WorkflowWorker实例都有完整的生命周期管理:

class WorkflowWorker {
  constructor(id, engine, options = {}) {
    this.id = id;                    // 线程唯一标识
    this.engine = engine;            // 所属引擎引用
    this.settings = engine.workflow.settings;
    this.blocksDetail = options.blocksDetail || {};
    
    // 线程状态变量
    this.loopEls = [];
    this.loopList = {};
    this.repeatedTasks = {};
    this.preloadScripts = [];
    this.breakpointState = null;
    
    this.windowId = null;
    this.currentBlock = null;
    this.childWorkflowId = null;
    this.debugAttached = false;
    
    // 活动标签页状态
    this.activeTab = {
      url: '',
      frameId: 0,
      frames: {},
      groupId: null,
      id: engine.options?.tabId,
    };
  }
}

状态同步机制

Automa实现了精细的状态同步系统,确保多个工作线程之间的数据一致性:

1. 引用数据管理
// 添加数据到列
addDataToColumn(key, value) {
  const columnId = this.engine.columns[key] ? key : this.engine.columnsId[key];
  const currentColumn = this.engine.columns[columnId];
  const columnName = currentColumn.name || 'column';
  const convertedValue = convertData(value, currentColumn.type);
  
  // 线程安全的数据操作
  if (objectHasKey(this.engine.referenceData.table, currentColumn.index)) {
    this.engine.referenceData.table[currentColumn.index][columnName] = convertedValue;
  } else {
    this.engine.referenceData.table.push({ [columnName]: convertedValue });
  }
  currentColumn.index += 1;
}
2. 变量同步
async setVariable(name, value) {
  let variableName = name;
  const vars = this.engine.referenceData.variables;
  
  // 处理数组推送操作
  if (name.startsWith('$push:')) {
    const { 1: varName } = name.split('$push:');
    if (!objectHasKey(vars, varName)) vars[varName] = [];
    else if (!Array.isArray(vars[varName])) vars[varName] = [vars[varName]];
    vars[varName].push(value);
    variableName = varName;
  } else {
    vars[name] = value;
  }
  
  // 持久化存储同步
  if (variableName.startsWith('$$')) {
    variableName = variableName.slice(2);
    const findStorageVar = await dbStorage.variables.get({ name: variableName });
    if (findStorageVar) await dbStorage.variables.update(findStorageVar.id, { value });
    else await dbStorage.variables.add({ name: variableName, value });
  }
  
  this.engine.addRefDataSnapshot('variables');
}

块执行与线程协作

工作线程之间的协作通过连接块机制实现:

executeNextBlocks(connections, prevBlockData, nextBlockBreakpointCount = null) {
  connections.forEach((connection, index) => {
    const { id, targetHandle, sourceHandle } = 
      typeof connection === 'string' 
        ? { id: connection, targetHandle: '', sourceHandle: '' } 
        : connection;
    
    const execParam = {
      prevBlockData,
      targetHandle,
      sourceHandle,
      nextBlockBreakpointCount,
    };
    
    if (index === 0) {
      // 当前线程继续执行
      this.executeBlock(this.engine.blocks[id], execParam);
    } else {
      // 创建新工作线程执行并行分支
      const state = cloneDeep({
        windowId: this.windowId,
        loopList: this.loopList,
        activeTab: this.activeTab,
        currentBlock: this.currentBlock,
        repeatedTasks: this.repeatedTasks,
        preloadScripts: this.preloadScripts,
        debugAttached: this.debugAttached,
      });
      
      this.engine.addWorker({ state, execParam, blockId: id });
    }
  });
}

断点与恢复机制

Automa支持复杂的断点调试功能,工作线程需要维护断点状态:

resume(nextBlock) {
  if (!this.breakpointState) return;
  
  const { block, execParam, isRetry } = this.breakpointState;
  const payload = { ...execParam, resume: true };
  payload.nextBlockBreakpointCount = nextBlock ? 1 : null;
  
  this.executeBlock(block, payload, isRetry);
  this.breakpointState = null;
}

线程间通信模式

Automa使用基于事件的通信模式实现线程间协调:

通信类型触发条件处理方式
数据更新变量修改通过引擎引用数据同步
状态变更块执行完成状态管理器统一处理
错误处理执行异常全局错误处理器
资源释放线程结束自动垃圾回收

性能优化策略

为了确保多线程环境下的性能,Automa实现了以下优化:

  1. 状态克隆优化:使用cloneDeep进行深度克隆,避免引用共享问题
  2. 内存管理:及时释放不再使用的线程状态
  3. 连接复用:重用浏览器连接,减少创建开销
  4. 批量操作:对存储操作进行批处理,减少I/O次数

容错与恢复

多线程环境下的错误处理至关重要:

async executeBlock(block, execParam = {}, isRetry = false) {
  const currentState = await this.engine.states.get(this.engine.id);
  
  // 状态检查确保线程有效性
  if (!currentState || currentState.isDestroyed) {
    if (this.engine.isDestroyed) return;
    await this.engine.destroy('stopped');
    return;
  }
  
  // 超时控制机制
  const timeoutMs = block.data?.settings?.blockTimeout;
  if (timeoutMs && timeoutMs > 0) {
    timeout = setTimeout(() => {
      reject(new Error('Timeout'));
    }, timeoutMs);
  }
}

这种多工作线程管理架构使得Automa能够高效处理复杂的自动化工作流,同时保持良好的可维护性和扩展性。通过精细的状态同步和线程协作机制,确保了即使在并发执行大量块的情况下,系统仍能保持稳定和高效。

数据引用与变量系统设计

Automa的数据引用与变量系统是其工作流自动化的核心基础设施,它提供了一个强大而灵活的机制来处理动态数据、状态管理和跨块通信。该系统采用了多层次的架构设计,支持从简单的变量替换到复杂的模板表达式求值。

变量存储架构

Automa的变量存储采用分层设计,包含以下几个关键数据源:

数据源类型存储位置生命周期访问方式
工作流变量内存存储工作流执行期间variables.key
全局数据扩展存储持久化存储globalData.key
表格数据IndexedDB跨工作流共享table[index].field
密钥数据加密存储安全持久化secrets.key
循环数据内存存储循环块内部loopData.data.field

mermaid

模板引擎实现

Automa的模板引擎支持两种语法模式:Mustache模板和JavaScript表达式。系统会自动检测并选择合适的渲染方式。

Mustache模板语法
// 基本变量引用
{{ variables.username }}

// 表格数据访问  
{{ table.0.email }}

// 函数调用
{{ $date('YYYY-MM-DD') }}

// 条件表达式
{{ variables.score > 90 ? '优秀' : '良好' }}
JavaScript表达式语法
// JS表达式(以!!开头)
!!variables.items.length > 0 ? '有数据' : '无数据'

// 复杂计算
!!Math.max(...variables.scores) * 1.1

数据引用解析流程

Automa的数据引用解析采用递归替换策略,确保嵌套表达式能够正确求值:

mermaid

变量作用域管理

Automa实现了精细的变量作用域控制,确保数据在不同上下文中的正确隔离和共享:

// 工作流引擎中的变量初始化
this.referenceData = {
  variables: {},        // 当前工作流变量
  table: [],            // 表格数据
  secrets: {},          // 加密凭证
  loopData: {},         // 循环块数据
  workflow: {},         // 工作流元数据
  googleSheets: {},     // Google Sheets数据
  globalData: {}        // 全局共享数据
};

// 变量快照机制(支持撤销/重做)
this.refDataSnapshots = {
  loopData: { index: 0, key: '##loopData0' },
  variables: { index: 0, key: '##variables0' }
};

安全沙箱执行

对于JavaScript表达式,Automa采用安全的沙箱执行环境:

// 沙箱消息通信机制
export function messageSandbox(type, data = {}) {
  return new Promise((resolve) => {
    const messageId = nanoid();
    const iframeEl = document.getElementById('sandbox');
    
    iframeEl.contentWindow.postMessage(
      { id: messageId, type, ...data }, 
      '*'
    );

    // 监听返回结果
    const messageListener = ({ data: messageData }) => {
      if (messageData?.id !== messageId) return;
      resolve(messageData.result);
    };
    
    window.addEventListener('message', messageListener);
  });
}

内置模板函数

Automa提供了丰富的内置模板函数,支持常见的数据处理需求:

函数类别函数名称功能描述示例
数学运算$multiply乘法运算{{ $multiply(variables.quantity, 2) }}
字符串处理$replace字符串替换{{ $replace(text, 'old', 'new') }}
日期时间$date日期格式化{{ $date('YYYY-MM-DD') }}
随机生成$randint随机整数{{ $randint(1, 100) }}
数据查询$filterJSONPath查询{{ $filter(data, '$.items[*]') }}

性能优化策略

Automa在变量系统设计中采用了多项性能优化措施:

  1. 惰性求值:只有在实际使用时才进行模板渲染
  2. 缓存机制:对频繁访问的数据进行缓存
  3. 批量处理:支持数组数据的批量模板替换
  4. 增量更新:只更新发生变化的数据部分
// 批量数组模板处理
if (Array.isArray(currentData)) {
  for (let index = 0; index < currentData.length; index += 1) {
    const value = currentData[index];
    const renderedValue = await renderString(value, data, isPopup);
    objectPath.set(copyBlock.data, `${blockDataKey}.${index}`, renderedValue.value);
  }
}

错误处理与回退机制

系统具备完善的错误处理能力,确保在变量解析失败时工作流不会完全中断:

// 安全的变量访问
function keyParser(key, data) {
  try {
    let [dataKey, path] = key.split(/[@.](.+)/);
    dataKey = refKeys[dataKey] ?? dataKey;
    
    if (!path) return { dataKey, path: '' };
    
    // 复杂的路径解析逻辑...
    return { dataKey, path };
  } catch (error) {
    // 返回原始键名作为回退
    return { dataKey: key, path: '' };
  }
}

这种设计使得Automa能够处理各种边界情况,包括变量不存在、路径错误、类型不匹配等问题,确保工作流的稳定执行。

总结

Automa的工作流引擎通过高度模块化和事件驱动的架构设计,实现了复杂自动化任务的高效执行。其核心优势体现在多工作线程模型的有效并行处理、精密的连接映射系统确保工作流智能流转、强大的数据引用与变量系统支持动态数据处理,以及完善的错误处理和恢复机制保障系统稳定性。引擎的性能优化策略,包括惰性求值、缓存机制和批量处理,进一步确保了大规模工作流的高效执行。这种架构设计使Automa能够处理从简单到复杂的各种浏览器自动化场景,提供了可靠且可扩展的自动化执行环境。

【免费下载链接】automa A browser extension for automating your browser by connecting blocks 【免费下载链接】automa 项目地址: https://gitcode.com/gh_mirrors/au/automa

创作声明:本文部分内容由AI辅助生成(AIGC),仅供参考

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

抵扣说明:

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

余额充值