Beispiel #1
0
        async Task <object> ContinueState(SuspendState state, WorkflowInstanceState workflowstate, WorkableLogger tasklogger, IDictionary <string, object> variables, CancellationToken token)
        {
            object lastresult = null;

            if (state.Subflow != null)
            {
                WorkflowIdentifier workflow = workflowstate.Workflow;
                workflowstate.Workflow = state.Subflow.Workflow;
                lastresult             = await ContinueState(state.Subflow, workflowstate, tasklogger, variables, token);

                workflowstate.Workflow = workflow;
            }
            else
            {
                if (variables != null)
                {
                    foreach (KeyValuePair <string, object> entry in variables)
                    {
                        state.Variables[entry.Key] = entry.Value.DetermineValue(state.Variables);
                    }
                }
            }

            InstanceTransition transition = await EvaluateTransitions(state.Node, tasklogger, state.Variables, state.Node.Transitions, token);

            if (transition == null)
            {
                tasklogger.Warning("Suspend node has no transition defined for current state. Workflow ends by default.");
                return(lastresult);
            }

            return(await Execute(workflowstate, token, transition.Target, lastresult));
        }
        private static SuspendState SuspendImpl(ICollection<ISuspendibleRegisteredObject> allRegisteredObjects) {
            // Our behavior is:
            // - We'll call each registered object's suspend method serially.
            // - All methods have a combined 5 seconds to respond, at which
            //   point we'll forcibly return to our caller.
            // - If a Resume call comes in, we'll not call any Suspend methods
            //   we haven't yet gotten around to, and we'll execute each
            //   resume callback we got.
            // - Resume callbacks may fire in parallel, even if Suspend methods
            //   fire sequentially.
            // - Resume methods fire asynchronously, so other events (such as
            //   Stop or a new Suspend call) could happen while a Resume callback
            //   is in progress.

            CountdownEvent countdownEvent = new CountdownEvent(2);
            SuspendState suspendState = new SuspendState(allRegisteredObjects);

            // Unsafe QUWI since occurs outside the context of a request.
            // We are not concerned about impersonation, identity, etc.

            // Invoke any registered subscribers to let them know that we're about
            // to suspend. This is done in parallel with ASP.NET's own cleanup below.
            if (allRegisteredObjects.Count > 0) {
                ThreadPool.UnsafeQueueUserWorkItem(_ => {
                    suspendState.Suspend();
                    countdownEvent.Signal();
                }, null);
            }
            else {
                countdownEvent.Signal(); // nobody is subscribed
            }

            // Release any unnecessary memory that we're holding on to. The GC will
            // be able to reclaim these, which means that we'll have to page in less
            // memory when the next request comes in.
            ThreadPool.UnsafeQueueUserWorkItem(_ => {
                // Release any char[] buffers we're keeping around
                HttpWriter.ReleaseAllPooledBuffers();

                // Trim expired entries from the runtime cache
                var cache = HttpRuntime.GetCacheInternal(createIfDoesNotExist: false);
                if (cache != null) {
                    cache.TrimCache(0);
                }

                // Trim all pooled HttpApplication instances
                HttpApplicationFactory.TrimApplicationInstances(removeAll: true);

                countdownEvent.Signal();
            }, null);

            if (Debug.IsDebuggerPresent()) {
                countdownEvent.Wait(); // to assist with debugging, don't time out if a debugger is attached
            }
            else {
                countdownEvent.Wait(_suspendMethodTimeout); // blocking call, ok for our needs since has finite wait time
            }
            return suspendState;
        }
Beispiel #3
0
        /// <inheritdoc />
        public override Task <object> Execute(WorkflowInstanceState state, CancellationToken token)
        {
            if (!string.IsNullOrEmpty(Parameters.Variable))
            {
                state.Variables[Parameters.Variable] = null;
            }
            SuspendState suspendstate = new SuspendState(state.Workflow, this, state.Variables, state.Language, state.Profiling);

            return(Task.FromResult((object)suspendstate));
        }
Beispiel #4
0
        /// <inheritdoc />
        public override async Task <object> Execute(WorkflowInstanceState state, CancellationToken token)
        {
            WorkflowInstance instance = await state.GetWorkflow(parameters.Name);

            WorkflowIdentifier parent = state.Workflow;

            state.Workflow = new WorkflowIdentifier(instance.Id, instance.Revision, instance.Name);
            object result = await state.WorkflowExecutor.Execute(instance, state.Logger, await Arguments.EvaluateArguments(state.Variables, token), state.Profiling, token);

            state.Workflow = parent;
            if (result is SuspendState suspend)
            {
                result = new SuspendState(state.Workflow, this, state.Variables, state.Language, state.Profiling, suspend);
            }

            return(result);
        }
 protected override void CreateStates()
 {
     StatePreRun = new PreRunState(this);
     StateRun = new RunState(this);
     StatePreStop = new PreStopState(this);
     StateStop = new StopState(this);
     StatePreInitialize = new PreInitializeState(this);
     StateInitialize = new InitializeState(this);
     StateRundown = new RundownState(this);
     StatePreEmergency = new PreEmergencyState(this);
     StateEmergency = new EmergencyState(this);
     StateEmergencyReset = new EmergencyResetState(this);
     StatePreAlarm = new PreAlarmState(this);
     StateAlarm = new AlarmState(this);
     StatePreWarning = new PreWarningState(this);
     StateWarning = new WarningState(this);
     StatePreSuspend = new PreSuspendState(this);
     StateSuspend = new SuspendState(this);
 }
        private static SuspendState SuspendImpl(ICollection <ISuspendibleRegisteredObject> allRegisteredObjects)
        {
            // Our behavior is:
            // - We'll call each registered object's suspend method serially.
            // - All methods have a combined 5 seconds to respond, at which
            //   point we'll forcibly return to our caller.
            // - If a Resume call comes in, we'll not call any Suspend methods
            //   we haven't yet gotten around to, and we'll execute each
            //   resume callback we got.
            // - Resume callbacks may fire in parallel, even if Suspend methods
            //   fire sequentially.
            // - Resume methods fire asynchronously, so other events (such as
            //   Stop or a new Suspend call) could happen while a Resume callback
            //   is in progress.

            CountdownEvent countdownEvent = new CountdownEvent(2);
            SuspendState   suspendState   = new SuspendState(allRegisteredObjects);

            // Unsafe QUWI since occurs outside the context of a request.
            // We are not concerned about impersonation, identity, etc.

            // Invoke any registered subscribers to let them know that we're about
            // to suspend. This is done in parallel with ASP.NET's own cleanup below.
            if (allRegisteredObjects.Count > 0)
            {
                ThreadPool.UnsafeQueueUserWorkItem(_ => {
                    suspendState.Suspend();
                    countdownEvent.Signal();
                }, null);
            }
            else
            {
                countdownEvent.Signal(); // nobody is subscribed
            }

            // Release any unnecessary memory that we're holding on to. The GC will
            // be able to reclaim these, which means that we'll have to page in less
            // memory when the next request comes in.
            ThreadPool.UnsafeQueueUserWorkItem(_ => {
                // Release any char[] buffers we're keeping around
                HttpWriter.ReleaseAllPooledBuffers();

                // Trim expired entries from the runtime cache
                var cache = HttpRuntime.GetCacheInternal(createIfDoesNotExist: false);
                if (cache != null)
                {
                    cache.TrimCache(0);
                }

                // Trim all pooled HttpApplication instances
                HttpApplicationFactory.TrimApplicationInstances(removeAll: true);

                countdownEvent.Signal();
            }, null);

            if (Debug.IsDebuggerPresent())
            {
                countdownEvent.Wait(); // to assist with debugging, don't time out if a debugger is attached
            }
            else
            {
                countdownEvent.Wait(_suspendMethodTimeout); // blocking call, ok for our needs since has finite wait time
            }
            return(suspendState);
        }