static void Interact(WorkflowApplication application) { IList <BookmarkInfo> bookmarks = application.GetBookmarks(); while (true) { Console.Write("Bookmarks:"); foreach (BookmarkInfo info in bookmarks) { Console.Write(" '" + info.BookmarkName + "'"); } Console.WriteLine(); Console.WriteLine("Enter the name of the bookmark to resume"); string bookmarkName = Console.ReadLine(); if (bookmarkName != null && !bookmarkName.Equals(string.Empty)) { Console.WriteLine("Enter the payload for the bookmark '{0}'", bookmarkName); string bookmarkPayload = Console.ReadLine(); BookmarkResumptionResult result = application.ResumeBookmark(bookmarkName, bookmarkPayload); if (result == BookmarkResumptionResult.Success) { return; } else { Console.WriteLine("BookmarkResumptionResult: " + result); } } } }
public Boolean Start(ILog data) { Variable <ILog> log = new Variable <ILog>("log", data); this.workflow = new Sequence { Activities = { new Caller() { BookmarkName = "Caller" }, new NewOpen() { BookmarkName = "NewOpen" }, } }; WorkflowApplication wfApp = new WorkflowApplication(workflow); AutoResetEvent idleEvent = new AutoResetEvent(false); wfApp.Idle = (WorkflowApplicationIdleEventArgs e) => { idleEvent.Set(); }; wfApp.Run(); BookmarkResumptionResult result = wfApp.ResumeBookmark("NewOpen", data); idleEvent.WaitOne(); return(result == BookmarkResumptionResult.Success); }
private bool ProcessResumption() { var stillSync = true; this.resumptionResult = this.instance.ResumeBookmarkCore(this.bookmark, this.value); if (this.resumptionResult == BookmarkResumptionResult.Success) { if (this.instance.Controller.HasPendingTrackingRecords) { var result = this.instance.Controller.BeginFlushTrackingRecords(this.timeoutHelper.RemainingTime(), this.PrepareAsyncCompletion(trackingCompleteCallback), this); if (result.CompletedSynchronously) { stillSync = OnTrackingComplete(result); } else { stillSync = false; } } } else if (this.resumptionResult == BookmarkResumptionResult.NotReady) { this.NotifyOperationComplete(); this.currentOperation = new DeferredRequiresIdleOperation(); } return(stillSync); }
private async Task <BookmarkResumptionResult> ResumeInstanceBookmarkAsync(Bookmark bookmark, object value, TimeSpan timeout) { await WaitIdleAsync(timeout); try { await PrepareAsync(); BookmarkResumptionResult result = await instance.ScheduleBookmarkResumptionAsync(bookmark, value); if (result == BookmarkResumptionResult.Success) { await instance.RunAsync(); } else { idle.Set(); } return(result); } catch { // TODO shouldn't we only set idle, if RunAsync() wasn't successful and instance.WorkflowInstanceState != WorkflowInstanceState.Runnable ??? idle.Set(); throw; } }
/// <summary> /// Initializes a new instance of the <see cref="BookmarkResumptionException"/> class. /// </summary> /// <param name="bookmarkName"> /// The bookmark Name. /// </param> /// <param name="result"> /// The result. /// </param> /// <param name="value">The resumption value </param> /// <param name="innerException"> /// The inner Exception. /// </param> public BookmarkResumptionException(string bookmarkName, BookmarkResumptionResult result, object value = null, Exception innerException = null) : base(string.Format(SR.Unable_to_resume_bookmark_name, bookmarkName, result), innerException) { this.BookmarkName = bookmarkName; this.Result = result; Value = value; }
private void ProcessBookmarkResumptionResult(Bookmark timerBookmark, BookmarkResumptionResult result) { switch (result) { case BookmarkResumptionResult.Success: case BookmarkResumptionResult.NotFound: lock (this.ThisLock) { if (!this.isDisposed) { this.RegisteredTimers.RemoveTimer(timerBookmark); } return; } break; case BookmarkResumptionResult.NotReady: break; default: return; } lock (this.ThisLock) { this.RegisteredTimers.RetryTimer(timerBookmark); } }
private void ProcessBookmarkResumptionResult(Bookmark timerBookmark, BookmarkResumptionResult result) { switch (result) { case BookmarkResumptionResult.NotFound: case BookmarkResumptionResult.Success: // The bookmark is removed maybe due to WF cancel, abort or the bookmark succeeds // no need to keep the timer around lock (this.ThisLock) { if (!this.isDisposed) { this.RegisteredTimers.RemoveTimer(timerBookmark); } } break; case BookmarkResumptionResult.NotReady: // The workflow maybe in one of these states: Completed, Aborted, Abandoned, unloading, Suspended // In the first 3 cases, we will let TimerExtension.CancelTimer take care of the cleanup. // In the 4th case, we want the timer to retry when it is loaded back, in all 4 cases we don't need to delete the timer // In the 5th case, we want the timer to retry until it succeeds. // Retry: lock (this.ThisLock) { this.RegisteredTimers.RetryTimer(timerBookmark); } break; } }
public async Task <BookmarkResumptionResult> ScheduleBookmarkResumptionAsync(Bookmark bookmark, object value) { BookmarkResumptionResult resumptionResult = Controller.ScheduleBookmarkResumption(bookmark, value); if (resumptionResult == BookmarkResumptionResult.Success) { await IfHasPendingThenFlushTrackingRecordsAsync(); } return(resumptionResult); }
// If the resumption didn't timed out nor aborted, but not found, it tries to return the previous response parameter if the operation was idempotent, // ie. throws OperationRepeatedException, or throws InvalidOperationException if the previous response is not known (didn't happen or not idempotent). private async Task <TResponseParameter> ResumeOperationBookmarkAsync <TResponseParameter>(string operationName, object requestResult, Type responseParameterType) where TResponseParameter : class { await WaitIdleAsync(Parameters.ResumeOperationTimeout); try { await PrepareAsync(); if (completionState == null) { TaskCompletionSource <TResponseParameter> taskCompletionSource = new TaskCompletionSource <TResponseParameter>(); BookmarkResumptionResult result = await instance.ScheduleOperationBookmarkResumptionAsync(operationName, new object[] { taskCompletionSource, requestResult }); WorkflowInstanceState workflowInstanceState = instance.WorkflowInstanceState; if (result == BookmarkResumptionResult.Success) { try { activeTaskCompletionSources.Add(taskCompletionSource); await instance.RunAsync(); return(await taskCompletionSource.Task); } finally { activeTaskCompletionSources.Remove(taskCompletionSource); } } else { if (result == BookmarkResumptionResult.NotReady && workflowInstanceState != WorkflowInstanceState.Complete) { // Instance is created but the initialization RunAsync() hasn't been called, this is impossible. throw new InvalidOperationException($"Instance state is '{workflowInstanceState}', instance is not ready to process operation '{operationName}'."); } else // NotFound or NotReady && Complete, though the later is also not possible at this point, completionState != null after prepare in that case { throw previousResponseParameterExtension.CreatePreviousResponseParameterException <TResponseParameter>(operationName, responseParameterType); } } } else { throw previousResponseParameterExtension.CreatePreviousResponseParameterException <TResponseParameter>(operationName, responseParameterType); } } catch { // TODO shouldn't we only set idle, if RunAsync() wasn't successful and instance.WorkflowInstanceState != WorkflowInstanceState.Runnable ??? idle.Set(); throw; } }
private static void OnResumeBookmarkComplete(IAsyncResult result) { if (result.CompletedSynchronously) { return; } BookmarkResumptionState state = (BookmarkResumptionState)result.AsyncState; BookmarkResumptionResult resumptionResult = state.Instance.EndResumeBookmark(result); state.TimerExtension.ProcessBookmarkResumptionResult(state.TimerBookmark, resumptionResult); }
void OnEndResumeBookmark(IAsyncResult ar) { object[] asyncState = ar.AsyncState as object[]; WorkflowApplication instance = asyncState[0] as WorkflowApplication; string bookmarkName = asyncState[1] as string; BookmarkResumptionResult result = instance.EndResumeBookmark(ar); if (result != BookmarkResumptionResult.Success) { //it is possible the bookmark has been removed by some other event in the workflow //but that event will update the host - no need to do it here this.hostView.OutputWriter.WriteLine("Could not resume bookmark: {0} on instance {1}", bookmarkName, instance.Id); } }
public async Task <BookmarkResumptionResult> ScheduleReminderBookmarkResumptionAsync(string reminderName) { BookmarkResumptionResult result = BookmarkResumptionResult.Success; if (!durableReminderExtension.IsReactivationReminder(reminderName)) { result = await ScheduleBookmarkResumptionAsync(durableReminderExtension.GetBookmark(reminderName), null); if (result != BookmarkResumptionResult.NotReady || WorkflowInstanceState == WorkflowInstanceState.Complete) // Success || NotFound || NotReady && Complete { durableReminderExtension.UnregisterReminder(reminderName); } } return(result); }
public void ResumeWorkFlow(BusinessObject.DtoModels.Game game) { Exception exception = new Exception(); Guid workflowInstanceID = game.InstanceId; SqlWorkflowInstanceStore store = new SqlWorkflowInstanceStore(databaseConnection); store.InstanceLockedExceptionAction = InstanceLockedExceptionAction.BasicRetry; store.HostLockRenewalPeriod = TimeSpan.FromSeconds(2); InstanceHandle instanceHandle = store.CreateInstanceHandle(); CreateWorkflowOwnerCommand createOwnerCmd = new CreateWorkflowOwnerCommand(); InstanceView view = store.Execute(instanceHandle, createOwnerCmd, TimeSpan.FromSeconds(10)); store.DefaultInstanceOwner = view.InstanceOwner; WorkflowApplicationInstance instance = WorkflowApplication.GetInstance(workflowInstanceID, store); AutoResetEvent syncEvent = new AutoResetEvent(false); WorkflowApplication wfApplication = new WorkflowApplication(new FlowchartNumberGuessWorkflow(), instance.DefinitionIdentity); wfApplication.PersistableIdle = (e) => PersistableIdleAction.Unload; wfApplication.Unloaded = (e) => { syncEvent.Set(); }; wfApplication.OnUnhandledException = (e) => { exception = e.UnhandledException; syncEvent.Set(); return(UnhandledExceptionAction.Cancel); }; wfApplication.Load(instance); BookmarkResumptionResult result = wfApplication.ResumeBookmark("Decision", game); syncEvent.WaitOne(); if (exception.Message != string.Empty && exception.StackTrace != null) { throw exception; } DeleteWorkflowOwnerCommand deleteOwnerCmd = new DeleteWorkflowOwnerCommand(); store.Execute(instanceHandle, deleteOwnerCmd, TimeSpan.FromSeconds(10)); }
public void ResumeBookmarkWhileTerminating() { s_exceptionType = typeof(TAC.ApplicationException); s_exceptionMsg = "I am throwing this Exception"; s_terminationReason = "Just cus!"; TestParallel parallel = new TestParallel("ParallelTest") { Branches = { new TestSequence("BlockingBranch") { Activities = { new TestWriteLine("BeforeBlocking") { Message = "I should be Executed", HintMessage = "I should be Executed" }, new TestBlockingActivity("Blocking", "BlockBranch") { ExpectedOutcome = Outcome.Faulted } } }, new TestTerminateWorkflow("TerminatingBranch") { ExceptionExpression = ((env) => new TAC.ApplicationException("I am throwing this Exception")), Reason = s_terminationReason, }, }, }; using (TestWorkflowRuntime testWorkflowRuntime = TestRuntime.CreateTestWorkflowRuntime(parallel)) { testWorkflowRuntime.OnWorkflowCompleted += new EventHandler <TestWorkflowCompletedEventArgs>(workflowInstance_Completed); testWorkflowRuntime.ExecuteWorkflow(); WaitForTerminationHelper(testWorkflowRuntime); // Try resuming the bookmark BookmarkResumptionResult result = testWorkflowRuntime.ResumeBookMark("Blocking", null); if (result != BookmarkResumptionResult.NotFound) { throw new TestCaseFailedException("Bookmark should be cancelled"); } } }
private async Task ResumeReminderBookmarkAsync(string reminderName) { await WaitIdleAsync(Parameters.ResumeInfrastructureTimeout); try { await PrepareAsync(); if (completionState == null) { BookmarkResumptionResult result = await instance.ScheduleReminderBookmarkResumptionAsync(reminderName); WorkflowInstanceState workflowInstanceState = instance.WorkflowInstanceState; if (result == BookmarkResumptionResult.Success) { await instance.RunAsync(); } else { if (result == BookmarkResumptionResult.NotReady && workflowInstanceState != WorkflowInstanceState.Complete) { // Instance is created but the initialization RunAsync() hasn't been called, this is impossible. throw new InvalidOperationException($"Instance state is '{workflowInstanceState}', instance is not ready to process reminder '{reminderName}'."); } else // NotFound or NotReady && Complete, though the later is also not possible at this point, completionState != null after prepare in that case // If we don't find a reminder, it's not an issue, maybe the grain/silo crashed after the reminder was created but before the workflow state was persisted, // or the grain/silo crashed after persistence but before the reminder was unregistered, // it will be unregistered on the next persistence event. // See ReminderTable for the detailed description of the algorithm. { idle.Set(); } } } else { await grain.UnregisterReminderAsync(reminderName); idle.Set(); } } catch { // TODO shouldn't we only set idle, if RunAsync() wasn't successful and instance.WorkflowInstanceState != WorkflowInstanceState.Runnable ??? idle.Set(); throw; } }
private static void OnResumeBookmarkComplete(IAsyncResult result) { if (!result.CompletedSynchronously) { BookmarkResumptionState asyncState = (BookmarkResumptionState)result.AsyncState; try { BookmarkResumptionResult result2 = asyncState.Instance.EndResumeBookmark(result); asyncState.TimerExtension.ProcessBookmarkResumptionResult(asyncState.TimerBookmark, result2); } catch (TimeoutException) { asyncState.TimerExtension.ProcessBookmarkResumptionResult(asyncState.TimerBookmark, BookmarkResumptionResult.NotReady); } } }
/// <summary> /// 从书签恢复 /// </summary> /// <param name="bookmarkName">书签名称</param> /// <param name="parameters">参数字典</param> /// <returns>恢复结果</returns> public void ResumeFromBookmark(string bookmarkName, IDictionary <string, object> parameters) { BookmarkResumptionResult result = this.WorkflowApplication.ResumeBookmark(bookmarkName, parameters); if (result == BookmarkResumptionResult.NotReady) { this.WorkflowApplication.Unload(); throw new ArgumentOutOfRangeException(nameof(bookmarkName), $"工作流实例\"{this.WorkflowInstanceId}\"的书签\"{bookmarkName}\"未准备就绪,请稍后再试!"); } if (result == BookmarkResumptionResult.NotFound) { this.WorkflowApplication.Unload(); throw new ArgumentOutOfRangeException(nameof(bookmarkName), $"工作流实例\"{this.WorkflowInstanceId}\"不存在书签\"{bookmarkName}\"!"); } }
private void CancelChildWorkItem(IList <Guid> parthToChild, NativeActivityContext context) { ICancellableWorkItemWithChildren cancellationRoot = RootWorkItem.Get(context).GoToChild(parthToChild) as ICancellableWorkItemWithChildren; if (cancellationRoot != null) { BookmarkResumptionResult cancelationRequestResult = context.ResumeBookmark( new Bookmark(WorkItemCancelationScope.CancelableWorkItemBookmarkName(cancellationRoot.Id)), cancellationRoot); if (cancelationRequestResult != BookmarkResumptionResult.Success) { WorkItemCancelationScope.MarkTasksAsCancelled(cancellationRoot, context, "Because cancellation request."); } } }
private async Task ResumeReminderBookmarkAsync(string reminderName) { BookmarkResumptionResult result = await ScheduleAndRunInstanceAsync(Parameters.ResumeInfrastructureTimeout, () => instance.ScheduleReminderBookmarkResumptionAsync(reminderName), (_result) => _result == BookmarkResumptionResult.Success); WorkflowInstanceState workflowInstanceState = instance.WorkflowInstanceState; if (result == BookmarkResumptionResult.NotReady && workflowInstanceState != WorkflowInstanceState.Complete) { // Instance is created but the initialization RunAsync() hasn't been called, this is impossible. throw new InvalidOperationException($"Instance state is '{workflowInstanceState}', instance is not ready to process reminder '{reminderName}'."); } //else // NotFound, Complete or Success // If we don't find a reminder, it's not an issue, maybe the grain/silo crashed after the reminder was created but before the workflow state was persisted, // or the grain/silo crashed after persistence but before the reminder was unregistered, // it will be unregistered on the next persistence event. // See ReminderTable for the detailed description of the algorithm. }
private void OnTimerFired(object state) { Bookmark nextExpiredBookmark; lock (this.ThisLock) { nextExpiredBookmark = this.RegisteredTimers.GetNextExpiredBookmark(); if ((nextExpiredBookmark == null) || (this.RegisteredTimers.GetNextDueTime() > DateTime.UtcNow)) { return; } } WorkflowInstanceProxy instance = this.instance; if (instance != null) { IAsyncResult result2 = null; bool completedSynchronously = false; try { result2 = instance.BeginResumeBookmark(nextExpiredBookmark, null, TimeSpan.FromSeconds(2.0), onResumeBookmarkComplete, new BookmarkResumptionState(nextExpiredBookmark, this, instance)); completedSynchronously = result2.CompletedSynchronously; } catch (TimeoutException) { this.ProcessBookmarkResumptionResult(nextExpiredBookmark, BookmarkResumptionResult.NotReady); } if (completedSynchronously && (result2 != null)) { try { BookmarkResumptionResult result = instance.EndResumeBookmark(result2); this.ProcessBookmarkResumptionResult(nextExpiredBookmark, result); } catch (TimeoutException) { this.ProcessBookmarkResumptionResult(nextExpiredBookmark, BookmarkResumptionResult.NotReady); } } } }
public void CancelWorkItem(List <Guid> rootToCanceledChildItemPath) { WorkflowApplication wfInstance; lock (_sinkRoot) { _runningWorkflows.TryGetValue(rootToCanceledChildItemPath[0], out wfInstance); } if (wfInstance != null) { Console.Write("cancellation requested for " + rootToCanceledChildItemPath[rootToCanceledChildItemPath.Count - 1]); string bookmarksBefore = String.Join(" , ", wfInstance.GetBookmarks().Select(bookmark => bookmark.BookmarkName).ToArray()); BookmarkResumptionResult bookmarkResumptionResult = wfInstance.ResumeBookmark(ProgressTrackingInitializer.CancellationBookmark, rootToCanceledChildItemPath); string bookmarksAfter = String.Join(" , ", wfInstance.GetBookmarks().Select(bookmark => bookmark.BookmarkName).ToArray()); } }
// If the resumption didn't timed out nor aborted, but not found, it tries to return the previous response parameter if the operation was idempotent, // ie. throws RepeatedOperationException, or throws InvalidOperationException if the previous response is not known (didn't happen or not idempotent). private async Task ResumeOperationBookmarkAsync <TResponseParameter>(string operationName, TaskCompletionSource <TResponseParameter> taskCompletionSource, object requestResult, Type responseParameterType, Func <object, RepeatedOperationException> createRepeatedOperationException) where TResponseParameter : class { BookmarkResumptionResult result = await ScheduleAndRunInstanceAsync(Parameters.ResumeOperationTimeout, () => instance.ScheduleOperationBookmarkResumptionAsync(operationName, new object[] { taskCompletionSource, requestResult }), (_result) => _result == BookmarkResumptionResult.Success, taskCompletionSource); WorkflowInstanceState workflowInstanceState = instance.WorkflowInstanceState; if (result == BookmarkResumptionResult.NotFound || result == BookmarkResumptionResult.NotReady && workflowInstanceState == WorkflowInstanceState.Complete) { previousResponseParameterExtension.ThrowPreviousResponseParameter(operationName, responseParameterType, createRepeatedOperationException); } else if (result == BookmarkResumptionResult.NotReady) // && !Complete // Instance is created but the initialization RunAsync() hasn't been called, this is impossible. { throw new InvalidOperationException($"Instance state is '{workflowInstanceState}', instance is not ready to process operation '{operationName}'."); } //else // Success }
bool PerformResumption() { // We always have the lock when entering this method bool waitFinishedSynchronously; bool completeSelf = false; // For ProtocolBookmark without Out-Of-Order messaging support, we will throw and // propagate Fault to client in case of invalid state (similar to management commands). // Otherwise, the result consistent with WorkflowApplication will be return and // the caller (eg. delay extension or OOM) needs to handle them accordingly. if (this.isResumeProtocolBookmark && this.instance.BufferedReceiveManager == null) { this.instance.ValidateStateForResumeProtocolBookmark(); } else { if (this.instance.AreBookmarksInvalid(out this.resumptionResult)) { return TrackPerformResumption(true); } } do { waitFinishedSynchronously = false; bool bufferedReceiveEnabled = this.isResumeProtocolBookmark && this.instance.BufferedReceiveManager != null; this.resumptionResult = this.instance.ResumeProtocolBookmarkCore(this.bookmark, this.value, this.bookmarkScope, bufferedReceiveEnabled, ref this.waitHandle, ref this.ownsLock); if (this.resumptionResult == BookmarkResumptionResult.NotReady && !bufferedReceiveEnabled) { if (nextIdleCallback == null) { nextIdleCallback = new Action<object, TimeoutException>(OnNextIdle); } if (this.waitHandle.WaitAsync(nextIdleCallback, this, !this.isResumeProtocolBookmark ? this.timeoutHelper.RemainingTime() : this.nextIdleTimeoutHelper.RemainingTime())) { // We now have the lock this.ownsLock = true; // We should retry the resumption synchronously waitFinishedSynchronously = true; } else { return false; } } else { completeSelf = true; break; } } while (waitFinishedSynchronously); return TrackPerformResumption(completeSelf); }
bool AreBookmarksInvalid(out BookmarkResumptionResult result) { if (this.hasRaisedCompleted) { result = BookmarkResumptionResult.NotFound; return true; } else if (this.state == State.Unloaded || this.state == State.Aborted || this.state == State.Suspended) { result = BookmarkResumptionResult.NotReady; return true; } result = BookmarkResumptionResult.Success; return false; }
public BookmarkResumptionResult TryGenerateWorkItem(ActivityExecutor executor, ref Bookmark bookmark, BookmarkScope scope, object value, System.Activities.ActivityInstance isolationInstance, bool nonScopedBookmarksExist, out ActivityExecutionWorkItem workItem) { BookmarkManager manager = null; Bookmark bookmark3; BookmarkCallbackWrapper wrapper2; BookmarkResumptionResult result3; workItem = null; BookmarkScope key = scope; if (scope.IsDefault) { key = this.defaultScope; } this.bookmarkManagers.TryGetValue(key, out manager); if (manager == null) { BookmarkResumptionResult notFound = BookmarkResumptionResult.NotFound; if (this.uninitializedScopes != null) { for (int i = 0; i < this.uninitializedScopes.Count; i++) { Bookmark bookmark2; BookmarkCallbackWrapper wrapper; BookmarkResumptionResult notReady; BookmarkScope scope3 = this.uninitializedScopes[i]; if (!this.bookmarkManagers[scope3].TryGetBookmarkFromInternalList(bookmark, out bookmark2, out wrapper)) { notReady = BookmarkResumptionResult.NotFound; } else if (this.IsExclusiveScopeUnstable(bookmark2)) { notReady = BookmarkResumptionResult.NotReady; } else { notReady = this.bookmarkManagers[scope3].TryGenerateWorkItem(executor, true, ref bookmark, value, isolationInstance, out workItem); } switch (notReady) { case BookmarkResumptionResult.Success: this.InitializeBookmarkScopeWithoutKeyAssociation(scope3, scope.Id); return(BookmarkResumptionResult.Success); case BookmarkResumptionResult.NotReady: notFound = BookmarkResumptionResult.NotReady; break; default: if ((notFound == BookmarkResumptionResult.NotFound) && !this.IsStable(scope3, nonScopedBookmarksExist)) { notFound = BookmarkResumptionResult.NotReady; } break; } } } return(notFound); } if (!manager.TryGetBookmarkFromInternalList(bookmark, out bookmark3, out wrapper2)) { result3 = BookmarkResumptionResult.NotFound; } else if (this.IsExclusiveScopeUnstable(bookmark3)) { result3 = BookmarkResumptionResult.NotReady; } else { result3 = manager.TryGenerateWorkItem(executor, true, ref bookmark, value, isolationInstance, out workItem); } if ((result3 == BookmarkResumptionResult.NotFound) && !this.IsStable(key, nonScopedBookmarksExist)) { result3 = BookmarkResumptionResult.NotReady; } return(result3); }
static bool HandleEndResumeBookmark(IAsyncResult result) { WorkflowOperationContext thisPtr = (WorkflowOperationContext)result.AsyncState; bool completed = false; bool shouldAbandon = true; try { BookmarkResumptionResult resumptionResult = thisPtr.workflowInstance.EndResumeProtocolBookmark(result); if (resumptionResult != BookmarkResumptionResult.Success) { // Raise UnkownMessageReceivedEvent when we fail to resume bookmark thisPtr.OperationContext.Host.RaiseUnknownMessageReceived(thisPtr.OperationContext.IncomingMessage); // Only delay-retry this operation once (and only if retries are supported). Future calls will ensure the bookmark is set. if (thisPtr.workflowInstance.BufferedReceiveManager != null) { bool bufferSuccess = thisPtr.workflowInstance.BufferedReceiveManager.BufferReceive( thisPtr.OperationContext, thisPtr.receiveContext, thisPtr.bookmark.Name, BufferedReceiveState.WaitingOnBookmark, false); if (bufferSuccess) { if (TD.BufferOutOfOrderMessageNoBookmarkIsEnabled()) { TD.BufferOutOfOrderMessageNoBookmark(thisPtr.eventTraceActivity, thisPtr.workflowInstance.Id.ToString(), thisPtr.bookmark.Name); } shouldAbandon = false; } } // The throw exception is intentional whether or not BufferedReceiveManager is set. // This is to allow exception to bubble up the stack to WCF to cleanup various state (like Transaction). // This is queue scenario and as far as the client is concerned, the client will not see any exception. throw FxTrace.Exception.AsError(new FaultException(OperationExecutionFault.CreateOperationNotAvailableFault(thisPtr.workflowInstance.Id, thisPtr.bookmark.Name))); } lock (thisPtr.thisLock) { if (thisPtr.CurrentState == State.ResultReceived) { thisPtr.CurrentState = State.Completed; if (thisPtr.pendingException != null) { throw FxTrace.Exception.AsError(thisPtr.pendingException); } completed = true; } else { thisPtr.CurrentState = State.WaitForResult; completed = false; } // we are not really completed until the ReceiveContext finishes its work if (completed) { completed = thisPtr.ProcessReceiveContext(); } shouldAbandon = false; } } finally { if (shouldAbandon) { BufferedReceiveManager.AbandonReceiveContext(thisPtr.receiveContext); } thisPtr.RemovePendingOperation(); } return(completed); }
public void Resume(Guid instandId, string bookmarkName, object info) { this.WFApplication.Load(instandId); BookmarkResumptionResult result = this.WFApplication.ResumeBookmark(bookmarkName, info); }
public BookmarkResumptionResult TryGenerateWorkItem(ActivityExecutor executor, ref Bookmark bookmark, BookmarkScope scope, object value, ActivityInstance isolationInstance, bool nonScopedBookmarksExist, out ActivityExecutionWorkItem workItem) { Fx.Assert(scope != null, "We should never have a null sub instance."); BookmarkManager manager = null; workItem = null; BookmarkScope lookupScope = scope; if (scope.IsDefault) { lookupScope = _defaultScope; } // We don't really care about the return value since we'll // use null to know we should check uninitialized sub instances _bookmarkManagers.TryGetValue(lookupScope, out manager); if (manager == null) { Fx.Assert(lookupScope != null, "The sub instance should not be default if we are here."); BookmarkResumptionResult finalResult = BookmarkResumptionResult.NotFound; // Check the uninitialized sub instances for a matching bookmark if (_uninitializedScopes != null) { for (int i = 0; i < _uninitializedScopes.Count; i++) { BookmarkScope uninitializedScope = _uninitializedScopes[i]; Fx.Assert(_bookmarkManagers.ContainsKey(uninitializedScope), "We must always have the uninitialized sub instances."); Bookmark internalBookmark; BookmarkCallbackWrapper callbackWrapper; BookmarkResumptionResult resumptionResult; if (!_bookmarkManagers[uninitializedScope].TryGetBookmarkFromInternalList(bookmark, out internalBookmark, out callbackWrapper)) { resumptionResult = BookmarkResumptionResult.NotFound; } else if (IsExclusiveScopeUnstable(internalBookmark)) { resumptionResult = BookmarkResumptionResult.NotReady; } else { resumptionResult = _bookmarkManagers[uninitializedScope].TryGenerateWorkItem(executor, true, ref bookmark, value, isolationInstance, out workItem); } if (resumptionResult == BookmarkResumptionResult.Success) { // We are using InitializeBookmarkScopeWithoutKeyAssociation because we know this is a new uninitialized scope and // the key we would associate is already associated. And if we did the association here, the subsequent call to // FlushBookmarkScopeKeys would try to flush it out, but it won't have the transaction correct so will hang waiting for // the transaction that has the PersistenceContext locked to complete. But it won't complete successfully until // we finish processing here. InitializeBookmarkScopeWithoutKeyAssociation(uninitializedScope, scope.Id); // We've found what we were looking for return(BookmarkResumptionResult.Success); } else if (resumptionResult == BookmarkResumptionResult.NotReady) { // This uninitialized sub-instance has a matching bookmark but // it can't currently be resumed. We won't return BookmarkNotFound // because of this. finalResult = BookmarkResumptionResult.NotReady; } else { if (finalResult == BookmarkResumptionResult.NotFound) { // If we still are planning on returning failure then // we'll incur the cost of seeing if this scope is // stable or not. if (!IsStable(uninitializedScope, nonScopedBookmarksExist)) { // There exists an uninitialized scope which is unstable. // At the very least this means we'll return NotReady since // this uninitialized scope might eventually contain this // bookmark. finalResult = BookmarkResumptionResult.NotReady; } } } } } return(finalResult); } else { Bookmark bookmarkFromList; BookmarkCallbackWrapper callbackWrapper; BookmarkResumptionResult resumptionResult; if (!manager.TryGetBookmarkFromInternalList(bookmark, out bookmarkFromList, out callbackWrapper)) { resumptionResult = BookmarkResumptionResult.NotFound; } else { if (IsExclusiveScopeUnstable(bookmarkFromList)) { resumptionResult = BookmarkResumptionResult.NotReady; } else { resumptionResult = manager.TryGenerateWorkItem(executor, true, ref bookmark, value, isolationInstance, out workItem); } } if (resumptionResult == BookmarkResumptionResult.NotFound) { if (!IsStable(lookupScope, nonScopedBookmarksExist)) { resumptionResult = BookmarkResumptionResult.NotReady; } } return(resumptionResult); } }
public ActionResult ToNextState(ItServiceItem isi, Guid instanceId, string NextLink, string libid, string Opinion) //审批者到下一环节,思路:保存当前流程的数据,恢复bookmark到下一环节,并保存下一环节流程信息 { #region 判断是不是当前处理人 WorkFlowItem cwfi = bdb.WorkFlowItems.Where(i => i.WfInstanceId == instanceId).FirstOrDefault(); string currentUserId = User.Identity.GetUserId(); ApplicationUser user = db.Users.Include(i => i.Roles).FirstOrDefault(i => i.Id == currentUserId); if (cwfi.WfCurrentUser.ToString().Trim() != user.UserName.ToString().Trim()) { var json = new { errorMsg = "你不是当前处理人" }; return(Json(json, "text/html", JsonRequestBehavior.AllowGet)); } #endregion string[] strs = NextLink.Trim().Split('('); AutoResetEvent syncEvent = new AutoResetEvent(false); int isComplete = 0; WorkflowApplication wfApp = new WorkflowApplication(new ItService()) { InstanceStore = CreateInstanceStore(), PersistableIdle = delegate(WorkflowApplicationIdleEventArgs e) { //var ex = e.GetInstanceExtensions<CustomTrackingParticipant>(); // Outputs = ex.First().Outputs.ToString(); return(PersistableIdleAction.Unload); }, Completed = delegate(WorkflowApplicationCompletedEventArgs e) { isComplete = 1; syncEvent.Set(); }, Aborted = delegate(WorkflowApplicationAbortedEventArgs e) { }, Unloaded = delegate(WorkflowApplicationEventArgs e) { syncEvent.Set(); }, OnUnhandledException = delegate(WorkflowApplicationUnhandledExceptionEventArgs e) { return(UnhandledExceptionAction.Terminate); }, Idle = delegate(WorkflowApplicationIdleEventArgs e) { } }; var StateTracker = new StateMachineStateTracker(wfApp.WorkflowDefinition); //当前状态追踪 wfApp.Extensions.Add(StateTracker); wfApp.Extensions.Add(new StateTrackerPersistenceProvider(StateTracker)); var cu = new CustomTrackingParticipant(); //获取Activity内部变量 wfApp.Extensions.Add(cu); //获取Activity内部变量需要的追踪器 //Guid instanceId = wfApp.Id; var trackerInstance = StateMachineStateTracker.LoadInstance(instanceId, wfApp.WorkflowDefinition, ConfigurationManager.ConnectionStrings["ApacheConnection"].ConnectionString); wfApp.Load(instanceId); BookmarkResumptionResult result = wfApp.ResumeBookmark(trackerInstance.CurrentState, strs[0]); //BookmarkResumptionResult result = wfApp.ResumeBookmark(trackerInstance.CurrentState, NextLink.Trim()); //恢复当前状态,并进入下一个bookmark,注意使用Trim,开始没使用,NextLInk无法取到,调试了大半夜 syncEvent.WaitOne(); string CurrentUser; string OpinionField = ""; string CurrentState; string completeStr = ""; if (isComplete == 0) { if (strs.Count() == 1) { CurrentUser = cu.Outputs["CurrentUser"].ToString(); } else { CurrentUser = db.LibraryApprovers.ToList().First(p => (p.LibID == libid) && (p.ApproverName == strs[1].Replace(")", ""))).Approver; } OpinionField = cu.Outputs["OpinionField"].ToString(); CurrentState = StateTracker.CurrentState; } else { CurrentUser = "******"; CurrentState = "已结束"; completeStr = "->结束"; } //string currentUserId = User.Identity.GetUserId(); //ApplicationUser user = db.Users.Include(i => i.Roles).FirstOrDefault(i => i.Id == currentUserId); //获取当前用户TrueName,为增加流转信息提供数据 WorkFlowItem wfi = bdb.WorkFlowItems.Where(i => i.WfInstanceId == instanceId).FirstOrDefault(); //获取当前流程信息 ItServiceItem cisi = bdb.ItServiceItems.Where(i => i.ID == isi.ID).FirstOrDefault(); //获取当前业务数据的信息 //业务数据更新开始 cisi.Title = isi.Title; cisi.applicant = isi.applicant; cisi.applicant_dept = isi.applicant_dept; //cisi.description = isi.description; cisi.isitype = isi.isitype; cisi.sub_isitype = isi.sub_isitype; cisi.end_isitype = isi.end_isitype; cisi.Object = isi.Object; cisi.Topic = isi.Topic; cisi.Purpose = isi.Purpose; cisi.Status = 1; if (NextLink == "驳回") { cisi.Status = 3; } if (isComplete == 1) { cisi.isiCompleteDate = DateTime.Now; if (NextLink == "撤销") { cisi.Status = 4; } else { cisi.Status = 2; } } #region 审批意见更新开始 if (Opinion != null) { if (Convert.ToString(Opinion) != "") { if (wfi.WfWriteField.Trim() == "FirstExamine") { cisi.FirstExamine = cisi.FirstExamine + "<br>" + Opinion + " (意见填写人:" + user.TrueName + " 时间:" + DateTime.Now + ")"; } if (wfi.WfWriteField.Trim() == "SecondExamine") { cisi.SecondExamine = cisi.SecondExamine + "<br>" + Opinion + " (意见填写人:" + user.TrueName + " 时间:" + DateTime.Now + ")"; } if (wfi.WfWriteField.Trim() == "LastExamine") { cisi.LastExamine = cisi.LastExamine + "<br>" + Opinion + " (意见填写人:" + user.TrueName + " 时间:" + DateTime.Now + ")"; } } } #endregion if (wfi != null) { wfi.WfCurrentUser = CurrentUser; wfi.Wfstatus = CurrentState; wfi.WfWriteField = OpinionField; if (isComplete == 1) { wfi.WfCompleteDate = DateTime.Now; } wfi.WfFlowChart = wfi.WfFlowChart + "->" + trackerInstance.CurrentState + "(" + user.TrueName + ")" + completeStr; //增加流转信息 try { bdb.SaveChanges(); var json = new { okMsg = "提交成功" }; return(Json(json, "text/html", JsonRequestBehavior.AllowGet)); } catch (Exception e) { var json = new { errorMsg = "提交失败" }; return(Json(json, "text/html", JsonRequestBehavior.AllowGet)); } } else { var json = new { errorMsg = "流程不存在" }; return(Json(json, "text/html", JsonRequestBehavior.AllowGet)); } }
void ProcessBookmarkResumptionResult(Bookmark timerBookmark, BookmarkResumptionResult result) { switch (result) { case BookmarkResumptionResult.NotFound: case BookmarkResumptionResult.Success: // The bookmark is removed maybe due to WF cancel, abort or the bookmark succeeds // no need to keep the timer around lock (this.ThisLock) { if (!this.isDisposed) { this.RegisteredTimers.RemoveTimer(timerBookmark); } } break; case BookmarkResumptionResult.NotReady: // The workflow maybe in one of these states: Completed, Aborted, Abandoned, unloading, Suspended // In the first 3 cases, we will let TimerExtension.CancelTimer take care of the cleanup. // In the 4th case, we want the timer to retry when it is loaded back, in all 4 cases we don't need to delete the timer // In the 5th case, we want the timer to retry until it succeeds. // Retry: lock (this.ThisLock) { this.RegisteredTimers.RetryTimer(timerBookmark); } break; } }
private bool PerformResumption() { bool flag; bool completeSelf = false; if (this.isResumeProtocolBookmark && (this.instance.BufferedReceiveManager == null)) { this.instance.ValidateStateForResumeProtocolBookmark(); } else if (this.instance.AreBookmarksInvalid(out this.resumptionResult)) { return this.TrackPerformResumption(true); } do { flag = false; bool bufferedReceiveEnabled = this.isResumeProtocolBookmark && (this.instance.BufferedReceiveManager != null); this.resumptionResult = this.instance.ResumeProtocolBookmarkCore(this.bookmark, this.value, this.bookmarkScope, bufferedReceiveEnabled, ref this.waitHandle, ref this.ownsLock); if ((this.resumptionResult == BookmarkResumptionResult.NotReady) && !bufferedReceiveEnabled) { if (nextIdleCallback == null) { nextIdleCallback = new Action<object, TimeoutException>(WorkflowServiceInstance.ResumeProtocolBookmarkAsyncResult.OnNextIdle); } if (!this.waitHandle.WaitAsync(nextIdleCallback, this, !this.isResumeProtocolBookmark ? this.timeoutHelper.RemainingTime() : this.nextIdleTimeoutHelper.RemainingTime())) { return false; } this.ownsLock = true; flag = true; } else { completeSelf = true; break; } } while (flag); return this.TrackPerformResumption(completeSelf); }
public ActionResult DrafterToNextState(ItServiceItem isi, Guid instanceId, string NextLink, string libid) //起草者到下一环节 { string[] strs = NextLink.Trim().Split('('); AutoResetEvent syncEvent = new AutoResetEvent(false); WorkflowApplication wfApp = new WorkflowApplication(new ItService()) { InstanceStore = CreateInstanceStore(), PersistableIdle = delegate(WorkflowApplicationIdleEventArgs e) { //var ex = e.GetInstanceExtensions<CustomTrackingParticipant>(); // Outputs = ex.First().Outputs.ToString();` return(PersistableIdleAction.Unload); }, Completed = delegate(WorkflowApplicationCompletedEventArgs e) { }, Aborted = delegate(WorkflowApplicationAbortedEventArgs e) { }, Unloaded = delegate(WorkflowApplicationEventArgs e) { syncEvent.Set(); }, OnUnhandledException = delegate(WorkflowApplicationUnhandledExceptionEventArgs e) { return(UnhandledExceptionAction.Terminate); }, Idle = delegate(WorkflowApplicationIdleEventArgs e) { } }; var StateTracker = new StateMachineStateTracker(wfApp.WorkflowDefinition); //当前状态追踪 wfApp.Extensions.Add(StateTracker); wfApp.Extensions.Add(new StateTrackerPersistenceProvider(StateTracker)); var cu = new CustomTrackingParticipant(); //获取Activity内部变量 wfApp.Extensions.Add(cu); //获取Activity内部变量需要的追踪器 //Guid instanceId = wfApp.Id; var trackerInstance = StateMachineStateTracker.LoadInstance(instanceId, wfApp.WorkflowDefinition, ConfigurationManager.ConnectionStrings["ApacheConnection"].ConnectionString); wfApp.Load(instanceId); //BookmarkResumptionResult result = wfApp.ResumeBookmark(trackerInstance.CurrentState, NextLink.Trim()); BookmarkResumptionResult result = wfApp.ResumeBookmark(trackerInstance.CurrentState, strs[0]); syncEvent.WaitOne(); //string CurrentUser = cu.Outputs["CurrentUser"].ToString(); string CurrentUser = db.LibraryApprovers.ToList().First(p => (p.LibID == libid) && (p.ApproverName == strs[1].Replace(")", ""))).Approver; //string CurrentRole = cu.Outputs["CurrentRole"].ToString(); string OpinionField = cu.Outputs["OpinionField"].ToString(); string Drafter = cu.Outputs["Drafter"].ToString(); var CurrentState = StateTracker.CurrentState; //var Pt = StateTracker.PossibleTransitions; ApplicationUser user = db.Users.Include(i => i.Roles).FirstOrDefault(i => i.UserName == Drafter); //获取当前用户username isi.drafter = Drafter; isi.isiCreateDate = DateTime.Now; isi.Status = 1; bdb.ItServiceItems.Add(isi); //添加业务数据 try { bdb.SaveChanges(); } catch { var json = new { errorMsg = "添加业务数据出错" }; return(Json(json, "text/html", JsonRequestBehavior.AllowGet)); } WorkFlowItem wf = new WorkFlowItem(); wf.WfInstanceId = instanceId; wf.WfType = "专病库IT服务申请"; wf.WfCurrentUser = CurrentUser; wf.WfDrafter = Drafter; wf.WfWriteField = OpinionField; wf.Wfstatus = CurrentState; wf.WfBussinessUrl = "/ItService/OpenWorkFlow?id=" + instanceId; wf.WfCreateDate = DateTime.Now; wf.WfBusinessId = isi.ID; //添加业务数据关联 wf.WfFlowChart = trackerInstance.CurrentState + "(" + user.TrueName + ")"; bdb.WorkFlowItems.Add(wf); bdb.SaveChanges(); try { bdb.SaveChanges(); var json = new { okMsg = "流程保存成功" }; return(Json(json, "text/html", JsonRequestBehavior.AllowGet)); } catch { var json = new { errorMsg = "流程保存出错" }; return(Json(json, "text/html", JsonRequestBehavior.AllowGet)); } }