@@ -265,65 +265,87 @@ func GetSignalChannel(ctx Context, signalName string) Channel {
265265	return  internal .GetSignalChannel (ctx , signalName )
266266}
267267
268- // SideEffect executes the provided function once, records its result into the workflow history. The recorded result on 
269- // history will be returned without executing the provided function during replay. This guarantees the deterministic 
270- // requirement for workflow as the exact same result will be returned in replay. 
271- // Common use case is to run some short non-deterministic code in workflow, like getting random number or new UUID. 
272- // The only way to fail SideEffect is to panic which causes decision task failure. The decision task after timeout is 
273- // rescheduled and re-executed giving SideEffect another chance to succeed. 
274- // 
275- // Caution: do not use SideEffect to modify closures. Always retrieve result from SideEffect's encoded return value. 
276- // For example this code is BROKEN: 
268+ // SideEffect executes the provided callback, and records its result into the workflow history. 
269+ // During replay the recorded result will be returned instead, so the callback can do non-deterministic 
270+ // things (such as reading files or getting random numbers) without breaking determinism during replay. 
271+ // 
272+ // As there is no error return, the callback's code is assumed to be reliable. 
273+ // If you cannot retrieve the value for some reason, panicking and failing the decision task 
274+ // will cause it to be retried, possibly succeeding on another machine. 
275+ // For better error handling, use ExecuteLocalActivity instead. 
276+ // 
277+ // Caution: the callback MUST NOT call any blocking or history-creating APIs, 
278+ // e.g. workflow.Sleep or ExecuteActivity or calling .Get on any future. 
279+ // This will (potentially) work during the initial recording of history, but will 
280+ // fail when replaying because the data is not available when the call occurs 
281+ // (it becomes available later). 
282+ // 
283+ // In other words, in general: use this *only* for code that does not need the workflow.Context. 
284+ // Incorrect context-using calls are not currently prevented in tests or during execution, 
285+ // but they should be eventually. 
286+ // 
287+ //	// Bad example: this will work until a replay occurs, 
288+ //	// but then the workflow will fail to replay with a non-deterministic error. 
289+ //	var out string 
290+ //	err := workflow.SideEffect(func(ctx workflow.Context) interface{} { 
291+ //		var signal data 
292+ //		err := workflow.GetSignalChannel(ctx, "signal").Receive(ctx, &signal) 
293+ //		_ = err // ignore err for the example 
294+ //		return signal 
295+ //	}).Get(&out) 
296+ //	workflow.GetLogger(ctx).Info(out) 
297+ // 
298+ // Caution: do not use SideEffect to modify values outside the callback. 
299+ // Always retrieve result from SideEffect's encoded return value. 
300+ // For example this code will break during replay: 
277301// 
278302//	// Bad example: 
279303//	var random int 
280304//	workflow.SideEffect(func(ctx workflow.Context) interface{} { 
281- //	        random = rand.Intn(100) 
282- //	        return nil 
305+ //		 random = rand.Intn(100) // this only occurs when recording history, not during replay  
306+ //		 return nil 
283307//	}) 
284308//	// random will always be 0 in replay, thus this code is non-deterministic 
285309//	if random < 50 { 
286- //	        .... 
310+ //		 .... 
287311//	} else { 
288- //	        .... 
312+ //		 .... 
289313//	} 
290314// 
291- // On replay the provided function is not executed, the random  will always be 0, and the workflow could takes a  
292- // different path breaking the  determinism. 
315+ // On replay the provided function is not executed, the ` random` var  will always be 0, 
316+ // and the workflow could take a  different path and break  determinism. 
293317// 
294- // Here is the correct  way to use SideEffect: 
318+ // The only safe  way to use SideEffect is to read from the returned encoded.Value : 
295319// 
296320//	// Good example: 
297321//	encodedRandom := SideEffect(func(ctx workflow.Context) interface{} { 
298- //	       return rand.Intn(100) 
322+ //		 return rand.Intn(100) 
299323//	}) 
300324//	var random int 
301325//	encodedRandom.Get(&random) 
302326//	if random < 50 { 
303- //	        .... 
327+ //		 .... 
304328//	} else { 
305- //	        .... 
329+ //		 .... 
306330//	} 
307331func  SideEffect (ctx  Context , f  func (ctx  Context ) interface {}) encoded.Value  {
308332	return  internal .SideEffect (ctx , f )
309333}
310334
311- // MutableSideEffect executes the provided function once, then it looks up the history for the value with the given id. 
312- // If there is no existing value, then it records the function result as a value with the given id on history; 
313- // otherwise, it compares whether the existing value from history has changed from the new function result by calling the 
314- // provided equals function. If they are equal, it returns the value without recording a new one in history; 
315- // 
316- //	otherwise, it records the new value with the same id on history. 
335+ // MutableSideEffect is similar to SideEffect, but it only records changed values per ID instead of every call. 
336+ // Changes are detected by calling the provided "equals" func - return true to mark a result 
337+ // as the same as before, and not record the new value.  The first call per ID is always "changed" and will always be recorded. 
317338// 
318- // Caution: do not use MutableSideEffect to modify closures. Always retrieve result from MutableSideEffect's encoded 
319- // return value. 
339+ // This is intended for things you want to *check* frequently, but which *change* only occasionally, as non-changing 
340+ // results will not add anything to your history.  This helps keep those workflows under its size/count limits, and 
341+ // can help keep replays more efficient than when using SideEffect or ExecuteLocalActivity (due to not storing duplicated data). 
320342// 
321- // The difference between MutableSideEffect() and SideEffect() is that every new SideEffect() call in non-replay will 
322- // result in a new marker being recorded on history. However, MutableSideEffect() only records a new marker if the value 
323- // changed. During replay, MutableSideEffect() will not execute the function again, but it will return the exact same 
324- // value as it was returning during the non-replay run. 
343+ // Caution: the callback MUST NOT block or call any history-modifying events, or replays will be broken. 
344+ // See SideEffect docs for more details. 
325345// 
326- // One good use case of MutableSideEffect() is to access dynamically changing config without breaking determinism. 
346+ // Caution: do not use MutableSideEffect to modify closures. 
347+ // Always retrieve result from MutableSideEffect's encoded return value. 
348+ // See SideEffect docs for more details. 
327349func  MutableSideEffect (ctx  Context , id  string , f  func (ctx  Context ) interface {}, equals  func (a , b  interface {}) bool ) encoded.Value  {
328350	return  internal .MutableSideEffect (ctx , id , f , equals )
329351}
0 commit comments