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); }
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); }
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); } }
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); }
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); }
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); }
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); }
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); } }
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); }
IDisposable IExecutionTaskContext.Track(IExecutionTask task) { AssertInitialized(); return(DiagnosticEvents.RunTask(task)); }
IDisposable IExecutionTaskContext.Track(IExecutionTask task) => DiagnosticEvents.RunTask(task);
private void ReportError(IExecutionTask task, IError error) { error = ErrorHandler.Handle(error); Result.AddError(error); DiagnosticEvents.TaskError(task, error); }
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); }
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); }
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); }