@@ -305,6 +305,64 @@ export class TaskHubGrpcClient {
305305 ) ;
306306 }
307307
308+ /**
309+ * Rewinds a failed orchestration instance to a previous state to allow it to retry from the point of failure.
310+ *
311+ * This method is used to "rewind" a failed orchestration back to its last known good state, allowing it
312+ * to be replayed from that point. This is particularly useful for recovering from transient failures
313+ * or for debugging purposes.
314+ *
315+ * Only orchestration instances in the `Failed` state can be rewound.
316+ *
317+ * @param instanceId - The unique identifier of the orchestration instance to rewind.
318+ * @param reason - A reason string describing why the orchestration is being rewound.
319+ * @throws {Error } If the orchestration instance is not found.
320+ * @throws {Error } If the orchestration instance is in a state that does not allow rewinding.
321+ * @throws {Error } If the rewind operation is not supported by the backend.
322+ */
323+ async rewindInstance ( instanceId : string , reason : string ) : Promise < void > {
324+ if ( ! instanceId ) {
325+ throw new Error ( "instanceId is required" ) ;
326+ }
327+
328+ const req = new pb . RewindInstanceRequest ( ) ;
329+ req . setInstanceid ( instanceId ) ;
330+
331+ if ( reason ) {
332+ const reasonValue = new StringValue ( ) ;
333+ reasonValue . setValue ( reason ) ;
334+ req . setReason ( reasonValue ) ;
335+ }
336+
337+ console . log ( `Rewinding '${ instanceId } ' with reason: ${ reason } ` ) ;
338+
339+ try {
340+ await callWithMetadata < pb . RewindInstanceRequest , pb . RewindInstanceResponse > (
341+ this . _stub . rewindInstance . bind ( this . _stub ) ,
342+ req ,
343+ this . _metadataGenerator ,
344+ ) ;
345+ } catch ( e ) {
346+ // Handle gRPC errors and convert them to appropriate errors
347+ if ( e && typeof e === "object" && "code" in e ) {
348+ const grpcError = e as { code : number ; details ?: string } ;
349+ if ( grpcError . code === grpc . status . NOT_FOUND ) {
350+ throw new Error ( `An orchestration with the instanceId '${ instanceId } ' was not found.` ) ;
351+ }
352+ if ( grpcError . code === grpc . status . FAILED_PRECONDITION ) {
353+ throw new Error ( grpcError . details || `Cannot rewind orchestration '${ instanceId } ': it is in a state that does not allow rewinding.` ) ;
354+ }
355+ if ( grpcError . code === grpc . status . UNIMPLEMENTED ) {
356+ throw new Error ( grpcError . details || `The rewind operation is not supported by the backend.` ) ;
357+ }
358+ if ( grpcError . code === grpc . status . CANCELLED ) {
359+ throw new Error ( `The rewind operation for '${ instanceId } ' was cancelled.` ) ;
360+ }
361+ }
362+ throw e ;
363+ }
364+ }
365+
308366 /**
309367 * Restarts an existing orchestration instance with its original input.
310368 *
0 commit comments