Automatisch Google Calendar 触发器全解析:New calendar 与 New event 的轮询机制与源码实现
2026/9/14 23:49:03 网站建设 项目流程

Automatisch Google Calendar 触发器全解析:New calendar 与 New event 的轮询机制与源码实现

【免费下载链接】automatischThe open source Zapier alternative. Build workflow automation without spending time and money.项目地址: https://gitcode.com/GitHub_Trending/au/automatisch

Google Calendar 是 Automatisch(开源 Zapier 替代品)内置的日历自动化应用,本指南以官方文档 triggers.md 为骨架,系统讲解其提供的New calendar(新建日历)New event(新建事件)两个触发器:从 Google Cloud OAuth 连接配置,到触发器的定义注册、分页拉取、去重与测试执行机制,并深入到 packages/backend/src/apps/google-calendar 的真实源码,带你掌握如何在流(Flow)中正确使用它们,以及它们底层"每 15 分钟轮询一次"的工作原理。读完本文,你将能够独立配置 Google Calendar 连接、理解触发器参数与去重行为,并能在自己的 Automatisch 实例上构建"当有新事件时发通知"一类的自动化流。

一、触发器总览:官方文档定义的两种触发场景

根据官方文档 triggers.md 的 frontmatter 元数据,Google Calendar 应用向用户开放两种触发器:

触发器名称标识 Key官方描述
New calendarnewCalendar当创建了一个新的日历时触发
New eventnewEvent当创建了一个新的事件时触发

在 Automatisch 文档站点中,这两个条目由items列表定义,通过 CustomListing.vue 组件渲染成可浏览的触发器清单页面。而在运行时,真正驱动自动化的是 triggers/index.js 导出的两个触发器实现:

import newCalendar from './new-calendar/index.js'; import newEvent from './new-event/index.js'; export default [newCalendar, newEvent];

该数组被 应用主入口 index.js 挂载到应用定义上:

export default defineApp({ name: 'Google Calendar', key: 'google-calendar', baseUrl: 'https://calendar.google.com', apiBaseUrl: 'https://www.googleapis.com/calendar', iconUrl: '{BASE_URL}/apps/google-calendar/assets/favicon.svg', authDocUrl: '{DOCS_URL}/apps/google-calendar/connection', primaryColor: '#448AFF', supportsConnections: true, beforeRequest: [addAuthHeader], auth, triggers, dynamicData, });

由此可见,两个触发器都是轮询型(polling)触发器,而非 Webhook 型。它们的共同特征是带有pollInterval属性,这一点在下一节会详细说明。

二、前置条件:配置 Google Calendar 连接(OAuth)

两个触发器都依赖用户授权的连接(Connection)。官方连接文档 connection.md 提供了完整的 Google Cloud 配置步骤,这里是完整继承并整理的实操流程:

  1. 前往Google Cloud Console创建一个项目(顶部项目下拉菜单 →New Project→ 填写项目名 →Create)。
  2. 进入API Library,搜索并启用Google Calendar API
  3. 重复上述操作,再启用People API(People API 用于获取当前用户信息,与授权范围相关,见下文)。
  4. 进入OAuth consent screen,首次开发选择External(外部)类型以测试模式启动,点击Create
  5. 填写App NameUser Support EmailDeveloper Contact Information,点击Save and Continue
  6. 跳过 scopes 配置页,点击Save and Continue
  7. 点击Add Users添加测试邮箱——当发布状态为 "Testing" 时,只有测试用户能访问应用。
  8. 点击Save and Continue完成同意屏幕配置。
  9. 进入Credentials,点击Create Credentials→ 选择OAuth client ID
  10. 应用类型选择Web application并填写Name
  11. 从 Automatisch 的 Google Calendar 连接表单中复制OAuth Redirect URL,粘贴到 Google 的Authorized redirect URIs字段,点击Create
  12. 将弹出的Your Client ID填入 Automatisch 的Client ID字段。
  13. 将弹出的Your Client Secret填入 Automatisch 的Client Secret字段。
  14. 点击 Automatisch 上的Submit,连接即建立,之后即可在流中使用。

从源码 auth/index.js 可以看到,连接表单正是要求OAuth Redirect URLClient IDClient Secret三个字段,其中重定向 URL 由系统自动填充为{WEB_APP_URL}/app/google-calendar/connections/add,并标记为只读(readOnly: true)与可点击复制(clickToCopy: true),便于直接粘贴到 Google Cloud 控制台。

OAuth 授权范围(Scope)

两个触发器请求的 Google 授权范围定义在 common/auth-scope.js:

const authScope = [ 'https://www.googleapis.com/auth/calendar', 'https://www.googleapis.com/auth/userinfo.email', 'https://www.googleapis.com/auth/userinfo.profile', ];

其中calendar范围赋予读取(及管理)日历与事件的权限,userinfo.emailuserinfo.profile用于在验证凭据时获取当前用户身份信息(见common/get-current-user.js)。这也解释了为什么连接文档要求同时启用 People API。

三、触发器定义规范:为什么它们必须是"轮询型"

查看 helpers/define-trigger.js 的校验逻辑可以确认:任何触发器要么声明pollInterval(轮询型),要么声明type === 'webhook'(Webhook 型),否则会在注册时直接抛出异常:

const isWebhookOrPoll = triggerDefinition.pollInterval || triggerDefinition.type === 'webhook'; const isSchedulerTrigger = schedulerTriggers.includes(triggerDefinition.key); const isMcpTrigger = triggerDefinition.key === 'mcpTool'; const haveValidTriggerType = isWebhookOrPoll || isSchedulerTrigger || isMcpTrigger; if (!haveValidTriggerType) { throw new Error( `Trigger must have a poll interval or be a webhook for ${triggerDefinition.key}` ); }

Google Calendar 的两个触发器均采用pollInterval: 15,即每 15 分钟由调度器触发一次轮询。这是理解其行为延迟的关键:新建事件后,触发器最多会在 15 分钟内被捕获,属于典型的近实时(near-real-time)方案,而非 Google Calendar 推送式实时回调。

四、New calendar 触发器源码解析

官方描述:Triggers when a new calendar is created(当创建新日历时触发)。完整实现位于 triggers/new-calendar/index.js:

export default defineTrigger({ name: 'New calendar', key: 'newCalendar', pollInterval: 15, description: 'Triggers when a new calendar is created.', arguments: [], async run($) { const params = { pageToken: undefined, maxResults: 250, }; do { const { data } = await $.http.get('/v3/users/me/calendarList', { params, }); params.pageToken = data.nextPageToken; if (data.items?.length) { for (const calendar of data.items.reverse()) { $.pushTriggerItem({ raw: calendar, meta: { internalId: calendar.etag, }, }); } } } while (params.pageToken); }, });

值得注意的实现细节:

  • 无需参数arguments为空数组,因为"当前用户的全部日历"由接口自动返回,不需要用户选择具体日历。
  • 分页拉取:调用GET /v3/users/me/calendarList获取当前用户的日历列表,每次最多 250 条(maxResults: 250),通过nextPageToken循环翻页直到取完所有页。
  • 时间倒序输出:对当页数据执行data.items.reverse(),使最新创建的日历排在最前,再由引擎按顺序处理。
  • 去重依据 internalId:使用日历资源的etag作为internalId。etag 是 Google API 资源的实体标签,同一日历的 etag 稳定不变,新建日历的 etag 则从未出现在历史记录中,因此天然适合作为"是否已处理过"的判定键。

五、New event 触发器源码解析

官方描述:Triggers when a new event is created(当创建新事件时触发)。完整实现位于 triggers/new-event/index.js:

export default defineTrigger({ name: 'New event', key: 'newEvent', pollInterval: 15, description: 'Triggers when a new event is created.', arguments: [ { label: 'Calendar', key: 'calendarId', type: 'dropdown', required: true, description: '', variables: false, source: { type: 'query', name: 'getDynamicData', arguments: [ { name: 'key', value: 'listCalendars', }, ], }, }, ], async run($) { const calendarId = $.step.parameters.calendarId; const params = { pageToken: undefined, orderBy: 'updated', }; do { const { data } = await $.http.get(`/v3/calendars/${calendarId}/events`, { params, }); params.pageToken = data.nextPageToken; if (data.items?.length) { for (const event of data.items.reverse()) { $.pushTriggerItem({ raw: event, meta: { internalId: event.etag, }, }); } } } while (params.pageToken); }, });

它与 New calendar 的关键差异:

  • 必须选择日历:声明了一个必填(required: true)的Calendar下拉参数(calendarId),即触发范围被限定在用户指定的某个日历内。
  • 下拉数据来自动态数据源:下拉框通过getDynamicData查询listCalendars动态数据源填充选项。该数据源实现在 dynamic-data/list-calendars/index.js,它同样调用GET /v3/users/me/calendarList并分页收集所有日历,最终把calendar.id作为选项值、calendar.summary作为展示名称:
for (const calendar of data.items) { drives.data.push({ value: calendar.id, name: calendar.summary, }); }
  • 按更新时间排序:请求携带orderBy: 'updated',让最近更新的事件排在前列,配合reverse()后,新创建(或新修改)的事件会被优先处理。注意这里"事件创建"在实现上体现为updated字段的排序——这是一个由源码得出的推断:只要事件的etag是新的,即便事件被修改也会被视为新的触发项(详见下一节的去重原理)。
  • 接口路径带日历 ID:实际请求为GET /v3/calendars/{calendarId}/events,其中calendarId来自步骤参数$.step.parameters.calendarId

六、轮询调度、去重与测试执行:触发器运行时的幕后机制

两个触发器都调用$.pushTriggerItem()提交触发项,其运行时行为定义在 engine/global-variable.js 中,理解这段逻辑是掌握触发器语义的核心:

pushTriggerItem: (triggerItem) => { if ( isAlreadyProcessed(triggerItem.meta.internalId) && !$.execution.testRun ) { // early exit as we do not want to process duplicate items in actual executions throw new AlreadyProcessedError(); } $.triggerOutput.data.push(triggerItem); if ($.execution.testRun && !isWebhookApp && !isFormsApp) { // early exit after receiving one item as it is enough for test execution throw new EarlyExitError(); } },

由此可以提炼出三个关键行为:

  1. 基于 internalId 去重:引擎会加载该流最近处理过的 internalId 列表(flow.lastInternalIds(2000),即保留最近 2000 条),当触发器提交的internalId已在列表中且当前不是测试运行(testRun)时,直接抛出AlreadyProcessedError终止本轮,避免同一个日历/事件被重复触发。这正是两个触发器都精心选用etag 作为 internalId的原因——etag 稳定且唯一。
  2. 测试运行提前终止:在测试模式下(testRun为 true),收到第一个触发项后立即抛出EarlyExitError结束执行——引擎只需一个样本即可验证触发器是否工作,无需等待分页全部完成。
  3. 去重窗口有限:由于只保留最近 2000 条 internalId,超过窗口后旧的记录会被淘汰。对于 Google Calendar 这种事件量较小的场景基本无感知,但在高频率创建日历/事件且流长期运行时不处理失败的情况下,理论上存在极低概率的重复触发,设计流程时可考虑配合其他去重手段。

轮询的调度节奏由pollInterval: 15决定——引擎按此间隔周期性调用run($)。这也意味着"新建事件后立即可用"并不成立,实际延迟取决于上一次轮询的时间点,最大约 15 分钟。

七、实战建议与适用范围

结合源码与官方文档,使用这两个触发器时有几点实用建议:

  • 选对触发器:监听"用户级"变化(任何日历被创建)用New calendar;监听"某日历内"变化用New event并明确选择目标日历。New event 的Calendar参数是必填的,建流时记得先完成 Google Calendar 连接,动态数据源才会返回可选项。
  • 理解延迟:两者都是 15 分钟轮询,不适合对时效性要求苛刻的场景;若需要秒级响应,应考虑其他实时通道(如直接消费 Google 推送通知,当前仓库未提供对应触发器)。
  • 数据下行字段:每个触发项都会把完整的日历/事件资源对象放在raw中,后续步骤可通过变量面板直接引用如事件标题、开始时间、日历名称等字段,无需额外 HTTP 请求。
  • 权限影响范围:授权的calendar范围是读写级(非只读calendar.readonly),请只在可信环境中使用自己的 OAuth 凭据。

八、总结

Google Calendar 应用的触发器以简洁的官方文档为入口(triggers.md),背后由一套完整的源码体系支撑:newCalendar监听GET /v3/users/me/calendarList的日历列表,newEvent借助listCalendars动态数据源选择日历后监听GET /v3/calendars/{calendarId}/events的事件列表;两者都以 15 分钟为轮询周期、以 etag 为去重标识,并通过defineTrigger校验与引擎的pushTriggerItem机制保证注册合法、执行幂等。掌握这些细节后,你就能在 Automatisch 中快速构建基于 Google Calendar 的自动化流,例如"新事件创建时发送 Slack 通知"或"新日历创建时写入 Google Sheets",并按需评估其 15 分钟延迟对业务场景的适配性。

【免费下载链接】automatischThe open source Zapier alternative. Build workflow automation without spending time and money.项目地址: https://gitcode.com/GitHub_Trending/au/automatisch

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

需要专业的网站建设服务?

联系我们获取免费的网站建设咨询和方案报价,让我们帮助您实现业务目标

立即咨询