4949/// dataConverter: { existing in EncryptingDataConverter(wrapping: existing) }
5050/// )
5151/// ```
52+ ///
53+ /// ## Bracketing the connect, run, and replay lifetimes
54+ ///
55+ /// To run setup or teardown around the connected-client, worker-run, or replay lifetimes, pass the
56+ /// matching `before`/`after` closures. The before closure runs immediately before the wrapped
57+ /// work, the after closure immediately after it returns successfully; if the wrapped work throws,
58+ /// the after closure does not run. If the before closure itself throws, the error propagates and
59+ /// neither the wrapped work nor the after closure runs. For full wrap semantics, such as
60+ /// short-circuiting or mapping errors, conform to ``ClientPlugin`` or ``WorkerPlugin`` directly
61+ /// and override the `connectClient(configuration:next:)`, `runWorker(configuration:next:)`, or
62+ /// `runReplayer(configuration:next:)` method.
5263public struct SimplePlugin : ClientPlugin , WorkerPlugin {
5364 /// A human-readable name used in diagnostics and ordering.
5465 public let name : String
@@ -68,6 +79,30 @@ public struct SimplePlugin: ClientPlugin, WorkerPlugin {
6879 /// Workflows the plugin registers with the worker and replayer.
6980 public let workflows : [ any WorkflowDefinition . Type ]
7081
82+ /// A closure invoked immediately before the inner work inside ``connectClient(configuration:next:)``.
83+ public let beforeConnect : ( @Sendable ( TemporalClient . Configuration) async throws -> Void ) ?
84+
85+ /// A closure invoked immediately after the inner work inside ``connectClient(configuration:next:)``.
86+ ///
87+ /// Does not run if the inner work throws.
88+ public let afterConnect : ( @Sendable ( TemporalClient . Configuration) async throws -> Void ) ?
89+
90+ /// A closure invoked immediately before the inner work inside ``runWorker(configuration:next:)``.
91+ public let beforeRunWorker : ( @Sendable ( TemporalWorker . Configuration) async throws -> Void ) ?
92+
93+ /// A closure invoked immediately after the inner work inside ``runWorker(configuration:next:)``.
94+ ///
95+ /// Does not run if the inner work throws.
96+ public let afterRunWorker : ( @Sendable ( TemporalWorker . Configuration) async throws -> Void ) ?
97+
98+ /// A closure invoked immediately before the inner work inside ``runReplayer(configuration:next:)``.
99+ public let beforeRunReplayer : ( @Sendable ( WorkflowReplayer . Configuration) async throws -> Void ) ?
100+
101+ /// A closure invoked immediately after the inner work inside ``runReplayer(configuration:next:)``.
102+ ///
103+ /// Does not run if the inner work throws.
104+ public let afterRunReplayer : ( @Sendable ( WorkflowReplayer . Configuration) async throws -> Void ) ?
105+
71106 /// Creates a new simple plugin.
72107 ///
73108 /// - Parameters:
@@ -80,20 +115,41 @@ public struct SimplePlugin: ClientPlugin, WorkerPlugin {
80115 /// Defaults to empty.
81116 /// - activities: Activities registered with the worker. Defaults to empty.
82117 /// - workflows: Workflows registered with the worker and replayer. Defaults to empty.
118+ /// - beforeConnect: An optional closure run immediately before the connected-client work.
119+ /// - afterConnect: An optional closure run immediately after the connected-client work
120+ /// returns successfully.
121+ /// - beforeRunWorker: An optional closure run immediately before the worker's run loop.
122+ /// - afterRunWorker: An optional closure run immediately after the worker's run loop returns
123+ /// successfully.
124+ /// - beforeRunReplayer: An optional closure run immediately before a single replay.
125+ /// - afterRunReplayer: An optional closure run immediately after a single replay returns
126+ /// successfully.
83127 public init (
84128 name: String ,
85129 dataConverter: ( @Sendable ( DataConverter ) -> DataConverter ) ? = nil ,
86130 clientInterceptors: [ any ClientInterceptor ] = [ ] ,
87131 workerInterceptors: [ any WorkerInterceptor ] = [ ] ,
88132 activities: [ any ActivityDefinition ] = [ ] ,
89- workflows: [ any WorkflowDefinition . Type ] = [ ]
133+ workflows: [ any WorkflowDefinition . Type ] = [ ] ,
134+ beforeConnect: ( @Sendable ( TemporalClient . Configuration) async throws -> Void ) ? = nil ,
135+ afterConnect: ( @Sendable ( TemporalClient . Configuration) async throws -> Void ) ? = nil ,
136+ beforeRunWorker: ( @Sendable ( TemporalWorker . Configuration) async throws -> Void ) ? = nil ,
137+ afterRunWorker: ( @Sendable ( TemporalWorker . Configuration) async throws -> Void ) ? = nil ,
138+ beforeRunReplayer: ( @Sendable ( WorkflowReplayer . Configuration) async throws -> Void ) ? = nil ,
139+ afterRunReplayer: ( @Sendable ( WorkflowReplayer . Configuration) async throws -> Void ) ? = nil
90140 ) {
91141 self . name = name
92142 self . dataConverter = dataConverter
93143 self . clientInterceptors = clientInterceptors
94144 self . workerInterceptors = workerInterceptors
95145 self . activities = activities
96146 self . workflows = workflows
147+ self . beforeConnect = beforeConnect
148+ self . afterConnect = afterConnect
149+ self . beforeRunWorker = beforeRunWorker
150+ self . afterRunWorker = afterRunWorker
151+ self . beforeRunReplayer = beforeRunReplayer
152+ self . afterRunReplayer = afterRunReplayer
97153 }
98154
99155 public func configure( _ configuration: inout TemporalClient . Configuration ) {
@@ -116,4 +172,33 @@ public struct SimplePlugin: ClientPlugin, WorkerPlugin {
116172 }
117173 configuration. interceptors. append ( contentsOf: workerInterceptors)
118174 }
175+
176+ public func connectClient< R: Sendable > (
177+ configuration: TemporalClient . Configuration ,
178+ next: ( ) async throws -> sending R
179+ ) async throws -> sending R {
180+ try await beforeConnect ? ( configuration)
181+ let result = try await next ( )
182+ try await afterConnect ? ( configuration)
183+ return result
184+ }
185+
186+ public func runWorker(
187+ configuration: TemporalWorker . Configuration ,
188+ next: ( ) async throws -> Void
189+ ) async throws {
190+ try await beforeRunWorker ? ( configuration)
191+ try await next ( )
192+ try await afterRunWorker ? ( configuration)
193+ }
194+
195+ public func runReplayer< R: Sendable > (
196+ configuration: WorkflowReplayer . Configuration ,
197+ next: ( ) async throws -> sending R
198+ ) async throws -> sending R {
199+ try await beforeRunReplayer ? ( configuration)
200+ let result = try await next ( )
201+ try await afterRunReplayer ? ( configuration)
202+ return result
203+ }
119204}
0 commit comments