コード例 #1
0
    private async Task ExecuteAsync(CancellationToken cancellationToken)
    {
        try
        {
            using (DiagnosticEvents.ResolveFieldValue(_resolverContext))
            {
                var success = await TryExecuteAsync(cancellationToken).ConfigureAwait(false);

                CompleteValue(success, cancellationToken);
            }

            Status = _completionStatus;
        }
        catch
        {
            // If an exception occurs on this level it means that something was wrong with the
            // operation context.

            // In this case we will mark the task as faulted and set the result to null.

            // However, we will not report or rethrow the exception since the context was already
            // destroyed and we would cause further exceptions.

            // The exception on this level is most likely caused by a cancellation of the request.
            Status = ExecutionTaskStatus.Faulted;
            _resolverContext.Result = null;
        }

        _operationContext.Scheduler.Complete(this);
        _objectPool.Return(this);
    }
コード例 #2
0
        public static bool HasWorkSessionId(RedisConnection redisConnection, string workSessionId, RedisOfficeStateStorageSettings settings)
        {
            var keyBunch = new KeyNameHelper(workSessionId);

            string[] keyArgs   = new string[] { keyBunch.StateKeyName };
            object[] valueArgs = new object[] { };

            string hasWorkSessionIdScript = @"
                local stateKeyName = KEYS[1]

                local status = redis.call('EXISTS', stateKeyName)
                local stateFound = status == 1

                local retValues = {} 
                retValues[1] = stateFound

                return retValues
            ";

            var results = (RedisResult[])(RedisResult)redisConnection.ScriptEvaluate(hasWorkSessionIdScript, keyArgs, valueArgs);

            bool stateFound = (bool)results[0];

#if DebugTest
            DiagnosticEvents.OnHasWorkSessionId(workSessionId, stateFound);
#endif

            return(stateFound);
        }
コード例 #3
0
        private async Task ExecuteAsync(CancellationToken cancellationToken)
        {
            try
            {
                using (DiagnosticEvents.ResolveFieldValue(ResolverContext))
                {
                    var success = await TryExecuteAsync(cancellationToken).ConfigureAwait(false);

                    CompleteValue(success, cancellationToken);
                }

                Status = _completionStatus;
            }
            catch
            {
                Status = ExecutionTaskStatus.Faulted;

                // we suppress any exception if the cancellation was requested.
                if (!cancellationToken.IsCancellationRequested)
                {
                    throw;
                }
            }
            finally
            {
                OperationContext.Scheduler.Complete(this);
                _objectPool.Return(this);
            }
        }
コード例 #4
0
        public static string FindWorkSessionId(RedisConnection redisConnection, string documentId)
        {
            var keyBunch = new KeyNameHelper("*", documentId);

            string[] keyArgs   = new string[] { keyBunch.DocumentIdToWorkSessionIdKeyName };
            object[] valueArgs = new object[] { };

            const string findScript = @"
                return getWorkSessionIdFromDocumentId(KEYS[1])
            ";
            var          results    = (RedisResult[])(RedisResult)redisConnection.ScriptEvaluate(getWorkSessionIdFromDocumentId + findScript, keyArgs, valueArgs);

            bool   workSessionIdFound = (bool)results[0];
            string workSessionId      = (string)results[1];

#if DebugTest
            DiagnosticEvents.OnFind(documentId, workSessionIdFound, workSessionId);
#endif

            if (workSessionIdFound)
            {
                return(workSessionId);
            }
            return(null);
        }
コード例 #5
0
        public static bool CheckOut(RedisConnection redisConnection, string lockerId, string workSessionId, RedisOfficeStateStorageSettings settings, out string state)
        {
            var keyBunch = new KeyNameHelper(workSessionId);

            string[] keyArgs   = new string[] { keyBunch.LockerKeyName, keyBunch.StateKeyName };
            object[] valueArgs = new object[] { lockerId, settings.LockerTTL };

            string checkOutScript = @"
                local lockerKeyName = KEYS[1]
                local stateKeyName = KEYS[2]

                local lockerId = ARGV[1]
                local lockerTTL = ARGV[2]

                local wasLockedByAnother = false
                local state = ''

                updateATime(stateKeyName)

                if checkStateExists(stateKeyName) then

                    wasLockedByAnother = tryToLock(lockerKeyName, lockerId, lockerTTL)
                    
                    if not wasLockedByAnother then
                        state = redis.call('GET', stateKeyName)
                    end

                end

                local retValues = {} 
                retValues[1] = wasLockedByAnother
                retValues[2] = state
                return retValues
            ";

            var atimeUpdateScript = GetAccessTimeUpdateScript(settings);

            var results = (RedisResult[])(RedisResult)redisConnection.ScriptEvaluate(atimeUpdateScript + checkStateExists + tryToLock + checkOutScript, keyArgs, valueArgs);

            bool wasLockedByAnother = (bool)results[0];

            state = (string)results[1];
            if (state == "")
            {
                state = null;
            }


#if DebugTest
            DiagnosticEvents.OnCheckOut(workSessionId, lockerId, wasLockedByAnother);
#endif
            if (wasLockedByAnother)
            {
                throw new CannotCheckoutStateCheckedOutByAnotherProcessException();
            }

            return(!wasLockedByAnother);
        }
コード例 #6
0
    private void ReportError(IExecutionTask task, IError error)
    {
        if (task is null)
        {
            throw new ArgumentNullException(nameof(task));
        }

        if (error is null)
        {
            throw new ArgumentNullException(nameof(error));
        }

        AssertInitialized();

        if (error is AggregateError aggregateError)
        {
            foreach (IError?innerError in aggregateError.Errors)
            {
                ReportSingle(innerError);
            }
        }
        else
        {
            ReportSingle(error);
        }

        void ReportSingle(IError singleError)
        {
            AddProcessedError(ErrorHandler.Handle(singleError));
        }

        void AddProcessedError(IError processed)
        {
            if (processed is AggregateError ar)
            {
                foreach (IError?ie in ar.Errors)
                {
                    Result.AddError(ie);
                    DiagnosticEvents.TaskError(task, ie);
                }
            }
            else
            {
                Result.AddError(processed);
                DiagnosticEvents.TaskError(task, processed);
            }
        }
    }
        private void ReportError(IExecutionTask task, IError error)
        {
            if (task is null)
            {
                throw new ArgumentNullException(nameof(task));
            }

            if (error is null)
            {
                throw new ArgumentNullException(nameof(error));
            }

            AssertInitialized();
            error = ErrorHandler.Handle(error);
            Result.AddError(error);
            DiagnosticEvents.TaskError(task, error);
        }
コード例 #8
0
 public static object Do(Func <object> task)
 {
     for (int tryIndex = 0; tryIndex < TryCount; tryIndex++)
     {
         bool lastTry = tryIndex == TryCount - 1;
         try {
             return(task());
         } catch (Exception e) {
             DiagnosticEvents.OnRedisOperationTryRepeaterTryException(e);
             if (lastTry || e is IDoNotRetryRedisOfficeException)
             {
                 throw e;
             }
             Thread.Sleep(TryInterval);
         }
     }
     return(null);
 }
コード例 #9
0
    public override async Task InvokeAsync(HttpContext context)
    {
        if (HttpMethods.IsPost(context.Request.Method) &&
            (context.GetGraphQLServerOptions()?.EnableMultipartRequests ?? true) &&
            ParseContentType(context) == AllowedContentType.Form)
        {
            if (!IsDefaultSchema)
            {
                context.Items[WellKnownContextData.SchemaName] = SchemaName.Value;
            }

            using (DiagnosticEvents.ExecuteHttpRequest(context, HttpRequestKind.HttpMultiPart))
            {
                await HandleRequestAsync(context, AllowedContentType.Form);
            }
        }
        else
        {
            // if the request is not a post multipart request or multipart requests are not enabled
            // we will just invoke the next middleware and do nothing:
            await NextAsync(context);
        }
    }
コード例 #10
0
        public static bool UndoCheckOut(RedisConnection redisConnection, string lockerId, string workSessionId, RedisOfficeStateStorageSettings settings)
        {
            var keyBunch = new KeyNameHelper(workSessionId);

            string[] keyArgs   = new string[] { keyBunch.LockerKeyName, keyBunch.StateKeyName };
            object[] valueArgs = new object[] { lockerId };

            string undoCheckOutScript = @"
                local locker_DeletedKeysCount = 0
                local lockerKeyName = KEYS[1]
                local stateKeyName = KEYS[2]
                local lockerId = ARGV[1]

                updateATime(stateKeyName)

                local wasLockedBy = redis.call('GET', lockerKeyName)
                local wasLockedByMe = wasLockedBy == lockerId
                if wasLockedByMe then
                    locker_DeletedKeysCount = redis.call('DEL', lockerKeyName)
                end

                local retValues = {} 
                    retValues[1] = locker_DeletedKeysCount
                return retValues
            ";

            var accesstimeUpdateScript = GetAccessTimeUpdateScript(settings);

            var results = (RedisResult[])(RedisResult)redisConnection.ScriptEvaluate(accesstimeUpdateScript + undoCheckOutScript, keyArgs, valueArgs);
            int locker_DeletedKeysCount = (int)results[0];

#if DebugTest
            DiagnosticEvents.OnUndoCheckOut(workSessionId, lockerId, locker_DeletedKeysCount);
#endif
            var success = locker_DeletedKeysCount == 1;
            return(success);
        }
コード例 #11
0
 IDisposable IExecutionTaskContext.Track(IExecutionTask task)
 {
     AssertInitialized();
     return(DiagnosticEvents.RunTask(task));
 }
コード例 #12
0
 IDisposable IExecutionTaskContext.Track(IExecutionTask task) =>
 DiagnosticEvents.RunTask(task);
コード例 #13
0
 private void ReportError(IExecutionTask task, IError error)
 {
     error = ErrorHandler.Handle(error);
     Result.AddError(error);
     DiagnosticEvents.TaskError(task, error);
 }
コード例 #14
0
        public static bool CheckIn(RedisConnection redisConnection, string lockerId, string workSessionId, string documentId, string state, RedisOfficeStateStorageSettings settings)
        {
            var keyBunch = new KeyNameHelper(workSessionId, documentId);

            string[] keyArgs   = new string[] { keyBunch.LockerKeyName, keyBunch.StateKeyName, keyBunch.DocumentIdToWorkSessionIdKeyName, keyBunch.WorkSessionIdToDocumentIdKeyName };
            object[] valueArgs = new object[] { lockerId, state, workSessionId, documentId };

            string checkInScript = @"
                local lockerKeyName = KEYS[1]
                local stateKeyName = KEYS[2]
                local documentIdToWorkSessionIdKeyName = KEYS[3]
                local workSessionIdToDocumentIdKeyName= KEYS[4]

                local lockerId = ARGV[1]
                local state = ARGV[2]
                local workSessionId = ARGV[3]
                local documentId = ARGV[4]

                local stateUpdateStatus = 'failed'
                local docIdToStateIdUpdateStatus = 'failed'
                local stateIdToDocIdUpdateStatus  = 'failed'
                local locker_DeletedKeysCount = 0

                updateATime(stateKeyName)
                
                local wasLockedBy = redis.call('GET', lockerKeyName)
                local lockerWasNotFound = type(wasLockedBy) == 'boolean' and not wasLockedBy
                local wasLocked = not lockerWasNotFound

                local wasLockedByMe = wasLockedBy == lockerId
                local wasLockedByAnother = wasLocked and not wasLockedByMe
                
                if not wasLockedByAnother then
                    stateUpdateStatus = redis.call('SET', stateKeyName, state)
                    setExpired(stateKeyName)
                    if not (documentId == nil or documentId == '') then
                        docIdToStateIdUpdateStatus = redis.call('SET', documentIdToWorkSessionIdKeyName, workSessionId)
                        stateIdToDocIdUpdateStatus = redis.call('SET', workSessionIdToDocumentIdKeyName, documentId)
                        setExpired(documentIdToWorkSessionIdKeyName)
                        setExpired(workSessionIdToDocumentIdKeyName)
                    end
                end
                if wasLockedByMe then
                    locker_DeletedKeysCount = redis.call('DEL', KEYS[1])
                end

                local retValues = {} 
                retValues[1] = stateUpdateStatus
                retValues[2] = locker_DeletedKeysCount
                retValues[3] = wasLockedByMe
                retValues[4] = wasLocked
                --[[
                docIdToStateIdUpdateStatus
                stateIdToDocIdUpdateStatus
                --]]

                return retValues
            ";

            var expireScript      = ExpireHelper.GetExpireScript(settings);
            var atimeUpdateScript = GetAccessTimeUpdateScript(settings);
            var script            = expireScript + atimeUpdateScript + checkInScript;
            var results           = (RedisResult[])(RedisResult)redisConnection.ScriptEvaluate(script, keyArgs, valueArgs);

            string stateUpdateStatus = (string)results[0];

#if DebugTest
            int  locker_DeletedKeysCount = (int)results[1];
            bool wasLockedByMe           = (bool)results[2];
            bool wasLocked = (bool)results[3];

            DiagnosticEvents.OnCheckIn(workSessionId, documentId, lockerId, stateUpdateStatus, locker_DeletedKeysCount, wasLockedByMe, wasLocked);
#endif
            bool success = stateUpdateStatus == "OK";

            return(success);
        }
コード例 #15
0
        internal static bool Remove(RedisConnection redisConnection, string lockerId, string workSessionId, RedisOfficeStateStorageSettings settings)
        {
            var keyBunch = new KeyNameHelper(workSessionId);

            string[] keyArgs   = new string[] { keyBunch.LockerKeyName, keyBunch.StateKeyName };
            object[] valueArgs = new object[] { lockerId, workSessionId };

            const string removeScriptTemplate = @"
                local lockerKeyName = KEYS[1]
                local stateKeyName = KEYS[2]

                local lockerId = ARGV[1]
                local workSessionId = ARGV[2]
                local lockerTTL = 1

                local wasLockedByAnother = tryToLock(lockerKeyName, lockerId, lockerTTL)

                local state_DeletedKeysCount = 0
                local stateToDoc_DeletedKeysCount = 0
                local docToState_DeletedKeysCount = 0
                local locker_DeletedKeysCount = 0

                if not wasLockedByAnother then
                    state_DeletedKeysCount = redis.call('DEL', stateKeyName)
                    removeATime(stateKeyName)

                    local stateToDocKeyName = workSessionId .. '{0}'
                    local docId = redis.call('GET', stateToDocKeyName)
                    local docIdFound = not (type(docId) == 'boolean' and not docId)

                    stateToDoc_DeletedKeysCount = redis.call('DEL', stateToDocKeyName)
                    
                    if docIdFound then
                        local docToStateKeyName = docId .. '{1}'
                        docToState_DeletedKeysCount = redis.call('DEL', docToStateKeyName)
                    end

                    locker_DeletedKeysCount = redis.call('DEL', lockerKeyName)
                end

                local retValues = {{}} 
                retValues[1] = wasLockedByAnother
                retValues[2] = state_DeletedKeysCount
                retValues[3] = stateToDoc_DeletedKeysCount
                retValues[4] = docToState_DeletedKeysCount
                retValues[5] = locker_DeletedKeysCount
                
                return retValues
            ";
            var          atimeRemoveScript    = GetAccessTimeUpdateScript(settings);

            string removeScript = string.Format(atimeRemoveScript + tryToLock + removeScriptTemplate, KeyNameHelper.WSToDocPostfix, KeyNameHelper.DocToWSPostfix);

            var results = (RedisResult[])(RedisResult)redisConnection.ScriptEvaluate(removeScript, keyArgs, valueArgs);

            var wasLockedByAnother     = (bool)results[0];
            var state_DeletedKeysCount = (int)results[1];

#if DebugTest
            var stateToDoc_DeletedKeysCount = (int)results[2];
            var docToState_DeletedKeysCount = (int)results[3];
            var locker_DeletedKeysCount     = (int)results[4];
            DiagnosticEvents.OnRemove(workSessionId, lockerId, wasLockedByAnother, state_DeletedKeysCount, stateToDoc_DeletedKeysCount, docToState_DeletedKeysCount, locker_DeletedKeysCount);
#endif
            if (wasLockedByAnother)
            {
                throw new CannotRemoveStateCheckedOutByAnotherProcessException();
            }
            return(true);
        }
コード例 #16
0
        internal static bool AddCheckedOut(RedisConnection redisConnection, string lockerId, string workSessionId, string documentId, RedisOfficeStateStorageSettings settings)
        {
            var keyBunch = new KeyNameHelper(workSessionId, documentId);

            string[] keyArgs   = new string[] { keyBunch.LockerKeyName, keyBunch.StateKeyName, keyBunch.DocumentIdToWorkSessionIdKeyName, keyBunch.WorkSessionIdToDocumentIdKeyName };
            object[] valueArgs = new object[] { lockerId, workSessionId, documentId, settings.LockerTTL };

            string addCheckedOutScript = @"
                local lockerKeyName = KEYS[1]
                local stateKeyName = KEYS[2]
                local documentIdToWorkSessionIdKeyName = KEYS[3]
                local workSessionIdToDocumentIdKeyName = KEYS[4]

                local lockerId = ARGV[1]
                local workSessionId = ARGV[2]
                local documentId = ARGV[3]
                local lockerTTL = ARGV[4]

                local stateUpdateStatus = 'failed'
                local docIdToStateIdUpdateStatus = 'failed'
                local stateIdToDocIdUpdateStatus  = 'failed'
                local wasLockedByAnother = false

                updateATime(stateKeyName)

                local documentIdSearch = getWorkSessionIdFromDocumentId(documentIdToWorkSessionIdKeyName)
                local sessionForThisDocumentIdFound = documentIdSearch[1];
                if not sessionForThisDocumentIdFound then

                    wasLockedByAnother = tryToLock(lockerKeyName, lockerId, lockerTTL)

                    local state = ''
                    if not wasLockedByAnother then
                        stateUpdateStatus = redis.call('SET', stateKeyName, state)
                        setExpired(stateKeyName)
                        if not (documentId == nil or documentId == '') then
                            docIdToStateIdUpdateStatus = redis.call('SET', documentIdToWorkSessionIdKeyName, workSessionId)
                            stateIdToDocIdUpdateStatus = redis.call('SET', workSessionIdToDocumentIdKeyName, documentId)
                            setExpired(documentIdToWorkSessionIdKeyName)
                            setExpired(workSessionIdToDocumentIdKeyName)
                        end
                    end
                end

                local retValues = {} 
                retValues[1] = sessionForThisDocumentIdFound
                retValues[2] = wasLockedByAnother

                retValues[3] = stateUpdateStatus
                retValues[4] = docIdToStateIdUpdateStatus
                retValues[5] = stateIdToDocIdUpdateStatus

                return retValues
            ";

            var expireScript      = ExpireHelper.GetExpireScript(settings);
            var atimeUpdateScript = GetAccessTimeUpdateScript(settings);
            var script            = expireScript + atimeUpdateScript + getWorkSessionIdFromDocumentId + tryToLock + addCheckedOutScript;
            var results           = (RedisResult[])(RedisResult)redisConnection.ScriptEvaluate(script, keyArgs, valueArgs);

            var sessionForThisDocumentIdFound = (bool)results[0];
            var wasLockedByAnother            = (bool)results[1];

            string stateUpdateStatus = (string)results[2];

#if DebugTest
            var docIdToStateIdUpdateStatus = (string)results[3];
            var stateIdToDocIdUpdateStatus = (string)results[4];

            DiagnosticEvents.OnAddCheckOut(workSessionId, documentId, lockerId, stateUpdateStatus, sessionForThisDocumentIdFound, wasLockedByAnother, docIdToStateIdUpdateStatus, stateIdToDocIdUpdateStatus);
#endif
            bool success = stateUpdateStatus == "OK";

            if (sessionForThisDocumentIdFound)
            {
                throw new CannotAddWorkSessionThatAlreadyExistsException();
            }

            return(success);
        }