Add client and worker plugin system#154
Draft
RalucaP wants to merge 4 commits into
Draft
Conversation
RalucaP
force-pushed
the
rppc/proto-plugins
branch
2 times, most recently
from
July 1, 2026 13:24
025530d to
2793595
Compare
Add `ClientPlugin` and `WorkerPlugin` protocols and a `plugins` field on the client, worker, and replayer configurations. `applyPlugins()` runs from the public connect/init entry points so callers don't invoke it manually, and the plugin list is snapshotted before the first `configure` runs so a plugin mutating `plugins` mid-pass doesn't affect the current apply. Defaults for `name` and `configure` mirror the Ruby and C# SDK plugin APIs.
Add empty-defaulted `activities` and `workflows` requirements to `WorkerPlugin`. The worker and replayer fold plugin contributions into their direct registrations before handing them off, so a plugin can ship its own activities/workflows without the caller wiring them up. Registrations are not deduplicated: contributing the same activity or workflow both directly and via a plugin throws a duplicate-registration error at startup. `TemporalWorker.init` documents this.
`SimplePlugin` bundles interceptors, activities, workflows, and an optional data-converter transform into a single value that conforms to both `ClientPlugin` and `WorkerPlugin`. One instance can be set on either configuration's `plugins`: on the client it customizes the client configuration; on the worker it customizes the worker (and replayer) configuration and contributes registered activities and workflows. The parameter shape mirrors the Ruby and C# SDK equivalents so plugin authors moving between SDKs see the same surface.
`ClientPlugin.connectClient` wraps both `TemporalClient.connect` and the `ServiceLifecycle` `run()`. `WorkerPlugin.runWorker` wraps `TemporalWorker.run`, and `WorkerPlugin.runReplayer` wraps each `replayWorkflow` call. Defaults forward to `next`, so existing plugins are unaffected. The chain helpers recurse over the plugin array rather than folding with `reduce`, which keeps the wrapped body non-`@escaping` and preserves the isolation semantics of `withGRPCClient`. First plugin in the array is the outermost wrap, matching Ruby and C#. `SimplePlugin` exposes the three wraps as optional `@Sendable` before/after closures, so authors can bracket the connect, worker-run, or replay lifetimes without a custom `ClientPlugin`/`WorkerPlugin` conformance. Matches Ruby's `connect_client`/`run_worker`/`with_workflow_replay_worker` hooks on `SimplePlugin` and C#'s `SimplePlugin` virtual lifecycle methods. Closes apple#111.
RalucaP
force-pushed
the
rppc/proto-plugins
branch
from
July 24, 2026 18:34
2793595 to
0fba0ec
Compare
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Sign up for free
to join this conversation on GitHub.
Already have an account?
Sign in to comment
Add this suggestion to a batch that can be applied as a single commit.This suggestion is invalid because no changes were made to the code.Suggestions cannot be applied while the pull request is closed.Suggestions cannot be applied while viewing a subset of changes.Only one suggestion per line can be applied in a batch.Add this suggestion to a batch that can be applied as a single commit.Applying suggestions on deleted lines is not supported.You must change the existing code in this line in order to create a valid suggestion.Outdated suggestions cannot be applied.This suggestion has been applied or marked resolved.Suggestions cannot be applied from pending reviews.Suggestions cannot be applied on multi-line comments.Suggestions cannot be applied while the pull request is queued to merge.Suggestion cannot be applied right now. Please check back later.
Closes #111.
Motivation
Today a single worker registers the activities and workflows for many domains in one place, which can blur ownership, and shared concerns like tracing or metrics get wired into each worker by hand. With plugins, each domain packages its own setup and registers itself, so the worker is just a list of plugins:
Design
The design follows the Ruby and C# SDKs where their shape maps well to Swift. A plugin registers activities, workflows, and interceptors, and can wrap lifecycle events like connecting a client, running a worker, or replaying a workflow. Plugins live on
Configurationand apply when the client connects or a worker or replayer starts.SimplePluginis the recommended starting point: it conforms to both theClientPluginandWorkerPluginprotocols, so one instance works on a client or a worker. Its before/after closures cover most needs. A plugin that must change a call rather than wrap it conforms to a protocol directly, which can skip the call, replace its result, or handle its error.Test plan
Ran the
PluginandLifecycleHooktests locally, all pass.References
client/plugin.rb,worker/plugin.rb,simple_plugin.rbITemporalClientPlugin.cs,ITemporalWorkerPlugin.cs,SimplePlugin.cs