@@ -123,6 +123,9 @@ public abstract class SimplePlugin
123123 private final List <BiConsumer <String , Worker >> workerShutdownCallbacks ;
124124 private final List <Consumer <WorkerFactory >> workerFactoryStartCallbacks ;
125125 private final List <Consumer <WorkerFactory >> workerFactoryShutdownCallbacks ;
126+ private final List <Consumer <WorkerOptions .Builder >> replayWorkerCustomizers ;
127+ private final List <BiConsumer <String , Worker >> replayWorkerInitializers ;
128+ private final List <BiConsumer <Worker , WorkflowExecutionHistory >> replayExecutionCallbacks ;
126129 private final List <WorkerInterceptor > workerInterceptors ;
127130 private final List <WorkflowClientInterceptor > clientInterceptors ;
128131 private final List <ContextPropagator > contextPropagators ;
@@ -151,6 +154,9 @@ protected SimplePlugin(@Nonnull String name) {
151154 this .workerShutdownCallbacks = Collections .emptyList ();
152155 this .workerFactoryStartCallbacks = Collections .emptyList ();
153156 this .workerFactoryShutdownCallbacks = Collections .emptyList ();
157+ this .replayWorkerCustomizers = Collections .emptyList ();
158+ this .replayWorkerInitializers = Collections .emptyList ();
159+ this .replayExecutionCallbacks = Collections .emptyList ();
154160 this .workerInterceptors = Collections .emptyList ();
155161 this .clientInterceptors = Collections .emptyList ();
156162 this .contextPropagators = Collections .emptyList ();
@@ -180,6 +186,9 @@ protected SimplePlugin(@Nonnull Builder builder) {
180186 this .workerShutdownCallbacks = new ArrayList <>(builder .workerShutdownCallbacks );
181187 this .workerFactoryStartCallbacks = new ArrayList <>(builder .workerFactoryStartCallbacks );
182188 this .workerFactoryShutdownCallbacks = new ArrayList <>(builder .workerFactoryShutdownCallbacks );
189+ this .replayWorkerCustomizers = new ArrayList <>(builder .replayWorkerCustomizers );
190+ this .replayWorkerInitializers = new ArrayList <>(builder .replayWorkerInitializers );
191+ this .replayExecutionCallbacks = new ArrayList <>(builder .replayExecutionCallbacks );
183192 this .workerInterceptors = new ArrayList <>(builder .workerInterceptors );
184193 this .clientInterceptors = new ArrayList <>(builder .clientInterceptors );
185194 this .contextPropagators = new ArrayList <>(builder .contextPropagators );
@@ -340,6 +349,41 @@ public void shutdownWorkerFactory(WorkerFactory factory, Runnable next) throws E
340349 next .run ();
341350 }
342351
352+ @ Override
353+ public void configureReplayWorker (
354+ @ Nonnull String taskQueue , @ Nonnull WorkerOptions .Builder builder ) {
355+ if (replayWorkerCustomizers .isEmpty ()) {
356+ // Default: delegate to configureWorker
357+ WorkerPlugin .super .configureReplayWorker (taskQueue , builder );
358+ } else {
359+ for (Consumer <WorkerOptions .Builder > customizer : replayWorkerCustomizers ) {
360+ customizer .accept (builder );
361+ }
362+ }
363+ }
364+
365+ @ Override
366+ public void initializeReplayWorker (@ Nonnull String taskQueue , @ Nonnull Worker worker ) {
367+ if (replayWorkerInitializers .isEmpty ()) {
368+ // Default: delegate to initializeWorker
369+ WorkerPlugin .super .initializeReplayWorker (taskQueue , worker );
370+ } else {
371+ for (BiConsumer <String , Worker > initializer : replayWorkerInitializers ) {
372+ initializer .accept (taskQueue , worker );
373+ }
374+ }
375+ }
376+
377+ @ Override
378+ public void replayWorkflowExecution (
379+ @ Nonnull Worker worker , @ Nonnull WorkflowExecutionHistory history , @ Nonnull Runnable next )
380+ throws Exception {
381+ next .run ();
382+ for (BiConsumer <Worker , WorkflowExecutionHistory > callback : replayExecutionCallbacks ) {
383+ callback .accept (worker , history );
384+ }
385+ }
386+
343387 @ Override
344388 public String toString () {
345389 return getClass ().getSimpleName () + "{name='" + name + "'}" ;
@@ -363,6 +407,10 @@ public static final class Builder {
363407 private final List <BiConsumer <String , Worker >> workerShutdownCallbacks = new ArrayList <>();
364408 private final List <Consumer <WorkerFactory >> workerFactoryStartCallbacks = new ArrayList <>();
365409 private final List <Consumer <WorkerFactory >> workerFactoryShutdownCallbacks = new ArrayList <>();
410+ private final List <Consumer <WorkerOptions .Builder >> replayWorkerCustomizers = new ArrayList <>();
411+ private final List <BiConsumer <String , Worker >> replayWorkerInitializers = new ArrayList <>();
412+ private final List <BiConsumer <Worker , WorkflowExecutionHistory >> replayExecutionCallbacks =
413+ new ArrayList <>();
366414 private final List <WorkerInterceptor > workerInterceptors = new ArrayList <>();
367415 private final List <WorkflowClientInterceptor > clientInterceptors = new ArrayList <>();
368416 private final List <ContextPropagator > contextPropagators = new ArrayList <>();
@@ -561,6 +609,59 @@ public Builder onWorkerFactoryShutdown(@Nonnull Consumer<WorkerFactory> callback
561609 return this ;
562610 }
563611
612+ // ==================== Replay Methods ====================
613+
614+ /**
615+ * Adds a customizer for {@link WorkerOptions} that is applied only when creating replay
616+ * workers. If no replay-specific customizers are set, the regular worker customizers are used.
617+ *
618+ * <p>Use this when replay workers need different configuration than normal workers.
619+ *
620+ * @param customizer a consumer that modifies the options builder
621+ * @return this builder for chaining
622+ */
623+ public Builder customizeReplayWorker (@ Nonnull Consumer <WorkerOptions .Builder > customizer ) {
624+ replayWorkerCustomizers .add (Objects .requireNonNull (customizer ));
625+ return this ;
626+ }
627+
628+ /**
629+ * Adds an initializer that is called after a replay worker is created. If no replay-specific
630+ * initializers are set, the regular worker initializers are used.
631+ *
632+ * <p>Use this when replay workers need different initialization than normal workers.
633+ *
634+ * @param initializer a consumer that receives the task queue name and worker
635+ * @return this builder for chaining
636+ */
637+ public Builder initializeReplayWorker (@ Nonnull BiConsumer <String , Worker > initializer ) {
638+ replayWorkerInitializers .add (Objects .requireNonNull (initializer ));
639+ return this ;
640+ }
641+
642+ /**
643+ * Adds a callback that is invoked after a workflow execution is replayed. This can be used for
644+ * logging, metrics, or other observability around replay operations.
645+ *
646+ * <p>Example:
647+ *
648+ * <pre>{@code
649+ * SimplePlugin.newBuilder("my-plugin")
650+ * .onReplayWorkflowExecution((worker, history) -> {
651+ * logger.info("Replayed workflow: {}", history.getWorkflowExecution().getWorkflowId());
652+ * })
653+ * .build();
654+ * }</pre>
655+ *
656+ * @param callback a consumer that receives the worker and history after replay completes
657+ * @return this builder for chaining
658+ */
659+ public Builder onReplayWorkflowExecution (
660+ @ Nonnull BiConsumer <Worker , WorkflowExecutionHistory > callback ) {
661+ replayExecutionCallbacks .add (Objects .requireNonNull (callback ));
662+ return this ;
663+ }
664+
564665 /**
565666 * Adds worker interceptors. Interceptors are appended to any existing interceptors in the
566667 * configuration.
0 commit comments