# Discourse 工作流

**URL:** https://meta.discourse.org/t/discourse-workflows/407100
**Category:** Plugin
**Tags:** official, included-in-core, workflows
**Created:** [2026年七月13日 01:54 UTC](https://meta.discourse.org/t/discourse-workflows/407100 "2026-07-13T01:54:16Z")
**Posts on this page:** 1
**Showing post:** 55

<div class="post-metadata">

### Author: ![j.jaffeux](https://sea3.discourse-cdn.com/meta/user_avatar/meta.discourse.org/j.jaffeux/32/60297_2.png) [@j.jaffeux](https://meta.discourse.org/u/j.jaffeux)
#### Post date: [2026年九月2日 14:41 UTC](https://meta.discourse.org/t/discourse-workflows/407100/55 "2026-09-02T14:41:36Z")

</div>

我们已在工作流中添加了以下内容：

> <https://github.com/discourse/discourse/commit/dd4cc4f4cc5aa73d8eb8efc3c154f4e139ff6052>
>
> Add the \`action:tag\_group\` workflow node for adding and removing tags.

> <https://github.com/discourse/discourse/commit/bd8b99b84bb3079862b3b18ec0249212f57b100d>
>
> Add a \`tag\_created\` workflow trigger with serialized tag payloads.

> <https://github.com/discourse/discourse/commit/0e80e895c354f1b524a1e8a8eda80d1ddf998c7c>
>
> Previously, the events plugin had no way to drive a workflow from an
> RSVP or fro…m an event finishing, and a trigger node contributed by any
> plugin was added to the registry but never subscribed to its
> \`DiscourseEvent\` — so it saved fine, showed up in the palette, and
> silently never fired.
> 
> This change wires the subscription into node registration, which drops
> the hand-rolled \`on(...)\` workarounds in assign, topic voting and chat,
> and adds \`trigger:event\_participation\_changed\` and
> \`trigger:event\_ended\`, both scopable to a single topic.
> 
> \---
> 
> Split into two commits, since the first touches shared infrastructure:
> 
> \- \*\*\`FIX: Subscribe trigger events for workflow nodes added by
> plugins\`\*\* — claiming a node now registers \*and\* subscribes it, and
> contributing plugins are flushed before the host claims its own, so
> ownership lands on them. Because the subscription goes through
> \`Plugin::Instance#on\`, a node stops listening while \*its own\* plugin is
> disabled rather than following the host's setting. This also drops a
> duplicate registration that let \`trigger:chat\_message\_created\` show in
> the palette while chat was disabled.
> \- \*\*\`FEATURE: Workflow triggers for event participation and event end\`\*\*
> — the two triggers. No \`on(...)\` wiring needed in the events plugin
> thanks to the commit above.
> 
> Three behaviour changes in the events plugin, each deliberate:
> 
> \- Withdrawing an RSVP destroyed the record without publishing anything,
> so attendance state built from these triggers could never recover from
> someone leaving. Removal now publishes, and reads as \`status: null\` with
> \`removed: true\`. The livestream chat sync skips removals, so its
> follow/unfollow behaviour is unchanged.
> \- The ended occurrence travels with \`:discourse\_post\_event\_event\_ended\`.
> \`set\_next\_date\` moves the event on immediately afterwards, and
> \`Event#starts\_at\` returns \`nil\` once a bounded series is past
> \`recurrence\_until\`, so the event alone cannot say which occurrence
> ended.
> \- Re-submitting an unchanged RSVP still publishes, so the trigger
> ignores it rather than running a workflow twice for one decision.
> 
> Payload is \`{event, post, topic, stats}\`, plus \`{user, participation}\`
> on the participation trigger — modelled on
> \`WebHook.build\_calendar\_event\_payload\` rather than \`EventSerializer\`,
> which goes admin-truthy under a system guardian. No JS, no core changes,
> no new site settings.
> 
> \### Known gaps, documented rather than fixed
> 
> Bulk invite, \`Event#create\_invitees\` (\`insert\_all!\`),
> \`reset\_invitee\_notifications\` (\`update\_all\`),
> \`enforce\_private\_invitees!\` (\`delete\_all\`) and event/user destroy stay
> silent. \`create\_attendance!\` swallows \`RecordNotUnique\`, so a concurrent
> first RSVP fires nothing. \`event\_ended\` can re-fire if an edit resets
> \`finished\_at\`, and is missed when an event is closed early:
> \`EventDate.pending\` merges \`Event.open\`, so the in-flight occurrence
> leaves the job's scope.
> 
> \`EventListener\` does not rescue \`new\`/\`valid?\`/\`matches?\` and
> \`DiscourseEvent.trigger\` re-raises, so a raising subscriber aborts
> \`MonitorEventDates\` mid-\`find\_each\`. Adding \`continue\_on\_error:\` there
> breaks existing \`track\_events\` assertions, so it is left for its own
> commit.
> 
> \### Testing
> 
> Full \`discourse-workflows\` and \`discourse-events\` backend suites pass
> (4005 examples), plus the workflow specs in chat, assign and topic
> voting. Verified at runtime that all 22 trigger nodes have exactly one
> subscription and there are no duplicate registrations, and that both new
> nodes disappear from the palette and stop dispatching when
> \`discourse\_events\_enabled\` is off.
> 
> Meta:
> https://meta.discourse.org/t/discourse-calendar-events-webhook-triggers-automations-plugin/409623
> 
> \---------
> 
> Co-authored-by: Joffrey JAFFEUX \<j.jaffeux@gmail.com\>

---

_[View the full topic](https://meta.discourse.org/t/discourse-workflows/407100)._
