@@ -33,6 +33,15 @@ const connectionString = process.env.AZURE_DTS_CONNECTION_STRING;
3333const endpoint = process . env . ENDPOINT || "localhost:8080" ;
3434const taskHub = process . env . TASKHUB || "default" ;
3535
36+ /**
37+ * Generates a unique instance ID with the given prefix.
38+ * @param prefix - The prefix for the instance ID
39+ * @returns A unique instance ID in the format: {prefix}-{timestamp}-{random}
40+ */
41+ function generateUniqueInstanceId ( prefix : string ) : string {
42+ return `${ prefix } -${ Date . now ( ) } -${ Math . random ( ) . toString ( 36 ) . substring ( 7 ) } ` ;
43+ }
44+
3645function createClient ( ) : TaskHubGrpcClient {
3746 const builder = new DurableTaskAzureManagedClientBuilder ( ) ;
3847 if ( connectionString ) {
@@ -74,27 +83,28 @@ describe("Rewind Instance E2E Tests", () => {
7483 } ) ;
7584
7685 describe ( "rewindInstance - positive cases" , ( ) => {
77- // Track execution attempt count for retry logic
78- let attemptCount = 0 ;
86+ // Track execution attempt count per instance ID for isolation across orchestrations
87+ const attemptCountByInstance = new Map < string , number > ( ) ;
7988
8089 // An orchestrator that fails on first attempt, succeeds on subsequent attempts
81- const failOnceOrchestrator : TOrchestrator = async ( _ctx : OrchestrationContext , _input : number ) => {
82- // Use input as a key to track attempts per instance
83- // After rewind, the orchestrator replays from the beginning
84- attemptCount ++ ;
85- if ( attemptCount === 1 ) {
90+ const failOnceOrchestrator : TOrchestrator = async ( ctx : OrchestrationContext , _input : number ) => {
91+ const instanceId = ctx . instanceId ;
92+ const currentAttempt = ( attemptCountByInstance . get ( instanceId ) ?? 0 ) + 1 ;
93+ attemptCountByInstance . set ( instanceId , currentAttempt ) ;
94+
95+ if ( currentAttempt === 1 ) {
8696 throw new Error ( "First attempt failed!" ) ;
8797 }
88- return `Success on attempt ${ attemptCount } ` ;
98+ return `Success on attempt ${ currentAttempt } ` ;
8999 } ;
90100
91101 beforeEach ( ( ) => {
92- attemptCount = 0 ;
102+ attemptCountByInstance . clear ( ) ;
93103 } ) ;
94104
95105 // Skip these tests if the backend doesn't support rewind (emulator returns UNIMPLEMENTED)
96106 it . skip ( "should rewind a failed orchestration instance (requires backend support)" , async ( ) => {
97- const instanceId = ` rewind-test- ${ Date . now ( ) } ` ;
107+ const instanceId = generateUniqueInstanceId ( " rewind-test" ) ;
98108
99109 taskHubWorker . addOrchestrator ( failOnceOrchestrator ) ;
100110 await startWorker ( ) ;
@@ -120,7 +130,7 @@ describe("Rewind Instance E2E Tests", () => {
120130 } ) ;
121131
122132 it . skip ( "should rewind a failed orchestration with a descriptive reason (requires backend support)" , async ( ) => {
123- const instanceId = ` rewind-reason- ${ Date . now ( ) } ` ;
133+ const instanceId = generateUniqueInstanceId ( " rewind-reason" ) ;
124134 const rewindReason = "Rewinding due to transient network failure" ;
125135
126136 taskHubWorker . addOrchestrator ( failOnceOrchestrator ) ;
@@ -153,15 +163,15 @@ describe("Rewind Instance E2E Tests", () => {
153163 } ;
154164
155165 it ( "should throw an error when rewinding a non-existent instance (or if rewind is not supported)" , async ( ) => {
156- const nonExistentId = ` non-existent- ${ Date . now ( ) } - ${ Math . random ( ) . toString ( 36 ) . substring ( 7 ) } ` ;
166+ const nonExistentId = generateUniqueInstanceId ( " non-existent" ) ;
157167
158168 // No need to start worker for this test
159169 // Will throw either "not found" or "not supported" depending on backend
160170 await expect ( taskHubClient . rewindInstance ( nonExistentId , "Test rewind" ) ) . rejects . toThrow ( ) ;
161171 } ) ;
162172
163173 it ( "should throw an error when rewinding a completed orchestration (or if rewind is not supported)" , async ( ) => {
164- const instanceId = ` rewind-completed- ${ Date . now ( ) } ` ;
174+ const instanceId = generateUniqueInstanceId ( " rewind-completed" ) ;
165175
166176 taskHubWorker . addOrchestrator ( simpleOrchestrator ) ;
167177 await startWorker ( ) ;
@@ -176,7 +186,7 @@ describe("Rewind Instance E2E Tests", () => {
176186 } ) ;
177187
178188 it . skip ( "should throw an error when rewinding a running orchestration (requires backend support)" , async ( ) => {
179- const instanceId = ` rewind-running- ${ Date . now ( ) } ` ;
189+ const instanceId = generateUniqueInstanceId ( " rewind-running" ) ;
180190
181191 taskHubWorker . addOrchestrator ( waitingOrchestrator ) ;
182192 await startWorker ( ) ;
@@ -201,7 +211,7 @@ describe("Rewind Instance E2E Tests", () => {
201211 } ) ;
202212
203213 it . skip ( "should throw an error when rewinding a terminated orchestration (requires backend support)" , async ( ) => {
204- const instanceId = ` rewind-terminated- ${ Date . now ( ) } ` ;
214+ const instanceId = generateUniqueInstanceId ( " rewind-terminated" ) ;
205215
206216 taskHubWorker . addOrchestrator ( waitingOrchestrator ) ;
207217 await startWorker ( ) ;
0 commit comments