private static void CompleteFailedTask(RevaleeTask task, string message) { Supervisor.State.CompleteTask(task); Supervisor.LogEvent(message, TraceEventType.Error); Supervisor.Telemetry.RecordWaitTime(CalculateWaitTime(DateTime.UtcNow, task)); Supervisor.Telemetry.RecordFailedCallback(); }
private static TimeSpan CalculateWaitTime(DateTime time, RevaleeTask task) { if (task.CallbackTime > task.CreatedTime) { if (task.CallbackTime < time) { return(time.Subtract(task.CallbackTime)); } else { return(TimeSpan.Zero); } } else { if (task.CreatedTime < time) { return(time.Subtract(task.CreatedTime)); } else { return(TimeSpan.Zero); } } }
private void ProcessWebException(RevaleeTask task, WebException wex) { HttpWebResponse failedResponse = (HttpWebResponse)wex.Response; if (failedResponse != null) { switch (DetermineResult(failedResponse.StatusCode)) { case CallbackResult.NonretryableError: CompleteFailedTask(task, FormatHttpErrorMessage(task, failedResponse.StatusCode)); break; default: CompleteRetryableTask(task, FormatHttpErrorMessage(task, failedResponse.StatusCode)); break; } } else { switch (DetermineResult(wex.Status)) { case CallbackResult.NonretryableError: CompleteFailedTask(task, FormatWebExceptionMessage(task, wex)); break; default: CompleteRetryableTask(task, FormatWebExceptionMessage(task, wex)); break; } } }
private static void CompleteFailedTask(RevaleeTask task, Exception exception) { Supervisor.State.CompleteTask(task); Supervisor.LogException(exception, TraceEventType.Error, task.CallbackUrl.OriginalString); Supervisor.Telemetry.RecordWaitTime(CalculateWaitTime(DateTime.UtcNow, task)); Supervisor.Telemetry.RecordFailedCallback(); }
private static HttpWebRequest PrepareWebRequest(RevaleeTask task) { HttpWebRequest request = (HttpWebRequest)WebRequest.Create(FormatCallbackRequestUrl(task.CallbackUrl)); request.ServicePoint.Expect100Continue = false; request.AllowAutoRedirect = true; request.MaximumAutomaticRedirections = 10; request.KeepAlive = false; request.Method = "POST"; request.Pipelined = false; request.Timeout = 30000; request.UserAgent = "Revalee"; request.ContentType = "application/x-www-form-urlencoded"; if (!string.IsNullOrEmpty(task.AuthorizationCipher)) { string responseCipher = BuildResponseAuthorizationCipher(task.AuthorizationCipher, task.CallbackId); if (responseCipher != null) { request.Headers.Add("Revalee-Auth", responseCipher); } } string postedData = FormatFormPayload(task); request.ContentLength = postedData.Length; using (Stream stream = request.GetRequestStream()) { stream.Write(Encoding.UTF8.GetBytes(postedData), 0, postedData.Length); } return(request); }
private static void CompleteSuccessfulTask(RevaleeTask task) { Supervisor.State.CompleteTask(task); Supervisor.LogEvent(string.Format("Successful callback to {0}. [{1}]", task.CallbackUrl.OriginalString, task.CallbackId), TraceEventType.Verbose); Supervisor.Telemetry.RecordWaitTime(CalculateWaitTime(DateTime.UtcNow, task)); Supervisor.Telemetry.RecordSuccessfulCallback(); RetryHeuristics.OnSuccess(task.CallbackUrl); }
private static void CompleteFailedTask(RevaleeTask task, HttpStatusCode statusCode) { Supervisor.State.CompleteTask(task); Supervisor.LogEvent(string.Format("Unsuccessful callback to {0} due to HTTP status code {1}. [{2}]", task.CallbackUrl.OriginalString, (int)statusCode, task.CallbackId), TraceEventType.Error); Supervisor.Telemetry.RecordWaitTime(CalculateWaitTime(DateTime.UtcNow, task)); Supervisor.Telemetry.RecordFailedCallback(); }
private void ProcessTask(object state) { RevaleeTask task = (RevaleeTask)state; if (!task.AttemptCallback()) { return; } try { HttpWebRequest request = PrepareWebRequest(task); Task <WebResponse> responseTask = Task.Factory.FromAsync <WebResponse>(request.BeginGetResponse, request.EndGetResponse, request); responseTask.ContinueWith(t => { HttpWebResponse response = null; try { response = (HttpWebResponse)t.Result; ProcessWebResponse(task, response); } catch (WebException wex) { ProcessWebException(task, wex); } catch (AggregateException aex) { WebException wex = ExtractWebException(aex); if (wex != null) { ProcessWebException(task, wex); } else { // Non-retryable error CompleteFailedTask(task, FormatGenericExceptionMessage(task, aex)); } } finally { if (response != null) { response.Close(); } } }); } catch (WebException wex) { ProcessWebException(task, wex); } catch (SecurityException sex) { // Non-retryable error CompleteFailedTask(task, FormatGenericExceptionMessage(task, sex)); } }
public void ReenlistTask(RevaleeTask task) { if (task == null) { throw new ArgumentNullException("task"); } _AwaitingTaskCollection.AddOrReplace(task.CallbackId, task, task.CallbackTime); ResetTaskAlarm(); }
private static void RetryTask(RevaleeTask task) { // Update the persisted attempt counts Supervisor.State.UpdateTask(task); // Reenlist task to be retried later TimeSpan retryDelay = RetryHeuristics.OnRetryableFailure(task.CallbackUrl); DateTime delayedCallbackTime = DateTime.UtcNow.Add(retryDelay); Supervisor.State.ReenlistTask(task, delayedCallbackTime); Supervisor.LogEvent(string.Format("Retrying callback to {0} after waiting {1}. [{2}]", task.CallbackUrl.OriginalString, retryDelay, task.CallbackId), TraceEventType.Information); }
private static void CompleteRetryableTask(RevaleeTask task, Exception exception) { if (task.AttemptsRemaining > 0) { RetryTask(task); } else { // Out of attempts CompleteFailedTask(task, exception); } }
private static void CompleteRetryableTask(RevaleeTask task, HttpStatusCode statusCode) { if (task.AttemptsRemaining > 0) { RetryTask(task); } else { // Out of attempts CompleteFailedTask(task, statusCode); } }
private static string FormatFormPayload(RevaleeTask task) { var payload = new StringBuilder(); payload.Append("CallbackId="); payload.Append(task.CallbackId.ToString("D")); payload.Append("&CallbackTime="); payload.Append(task.CallbackTime.ToString(@"yyyy-MM-dd\THH:mm:ss.fff\Z", CultureInfo.InvariantCulture)); payload.Append("&CurrentServiceTime="); payload.Append(DateTime.UtcNow.ToString(@"yyyy-MM-dd\THH:mm:ss.fff\Z", CultureInfo.InvariantCulture)); return(payload.ToString()); }
public void CompleteTask(RevaleeTask task) { if (task == null) { throw new ArgumentNullException("task"); } lock (_SyncRoot) { _PersistenceProvider.RemoveTask(task); Supervisor.Telemetry.DecrementAwaitingTasksValue(); } }
public void UpdateTask(RevaleeTask task) { if (task == null) { throw new ArgumentNullException("task"); } lock (_SyncRoot) { _PersistenceProvider.RemoveTask(task); _PersistenceProvider.AddTask(task); } }
private static void CompleteRetryableTask(RevaleeTask task, string message) { if (task.AttemptsRemaining > 0) { Supervisor.LogEvent(message, TraceEventType.Warning); RetryTask(task); } else { // Out of attempts CompleteFailedTask(task, message); } }
public void ReenlistTask(RevaleeTask task, DateTime due) { if (task == null) { throw new ArgumentNullException("task"); } if (due.Kind != DateTimeKind.Utc) { throw new ArgumentException("DateTime argument not provided in UTC.", "due"); } _AwaitingTaskCollection.AddOrReplace(task.CallbackId, task, due); ResetTaskAlarm(); }
public void AddTask(RevaleeTask task) { if (task == null) { throw new ArgumentNullException("task"); } lock (_SyncRoot) { _PersistenceProvider.AddTask(task); } _AwaitingTaskCollection.AddOrReplace(task.CallbackId, task, task.CallbackTime); Supervisor.Telemetry.IncrementAwaitingTasksValue(); ResetTaskAlarm(); }
private void ProcessWebResponse(RevaleeTask task, HttpWebResponse response) { switch (DetermineResult(response.StatusCode)) { case CallbackResult.Success: CompleteSuccessfulTask(task); break; case CallbackResult.NonretryableError: CompleteFailedTask(task, FormatHttpErrorMessage(task, response.StatusCode)); break; default: CompleteRetryableTask(task, FormatHttpErrorMessage(task, response.StatusCode)); break; } }
public void CancelTask(RevaleeTask task) { if (task == null) { throw new ArgumentNullException("task"); } RevaleeTask awaitingTask; if (_AwaitingTaskCollection.TryGetValue(task.CallbackId, out awaitingTask)) { if (awaitingTask.CallbackUrl.ToString().StartsWith(task.CallbackUrl.ToString(), StringComparison.OrdinalIgnoreCase)) { RevaleeTask removedTask; bool wasTaskRemoved = _AwaitingTaskCollection.TryRemove(awaitingTask.CallbackId, out removedTask); lock (_SyncRoot) { _PersistenceProvider.RemoveTask(awaitingTask); } if (wasTaskRemoved) { Supervisor.Telemetry.DecrementAwaitingTasksValue(); } } } else { RevaleeTask storedTask = RetrieveTask(task.CallbackId); if (storedTask != null) { if (storedTask.CallbackUrl.ToString().StartsWith(task.CallbackUrl.ToString(), StringComparison.OrdinalIgnoreCase)) { lock (_SyncRoot) { _PersistenceProvider.RemoveTask(storedTask); } } } } }
public void AddTask(RevaleeTask Task) { return; }
private static string FormatHttpErrorMessage(RevaleeTask task, HttpStatusCode statusCode) { return(string.Format("Unsuccessful callback to {0} due to HTTP status code {1}. [{2}]", task.CallbackUrl.OriginalString, (int)statusCode, task.CallbackId)); }
public void RemoveTask(RevaleeTask Task) { return; }
private void ProcessTask(object state) { RevaleeTask task = (RevaleeTask)state; if (!task.AttemptCallback()) { return; } try { HttpWebRequest request = PrepareWebRequest(task); Task <WebResponse> responseTask = Task.Factory.FromAsync <WebResponse>(request.BeginGetResponse, request.EndGetResponse, request); responseTask.ContinueWith(t => { try { HttpWebResponse response = null; try { response = (HttpWebResponse)t.Result; ProcessWebResponse(task, response); } catch (AggregateException aex) { if (aex.InnerExceptions.Count == 1 && aex.InnerExceptions[0] is WebException) { ProcessWebException(task, aex.InnerExceptions[0] as WebException); } else { aex = aex.Flatten(); if (aex.InnerExceptions.Count > 0) { throw aex.InnerExceptions[0]; } else { throw; } } } finally { if (response != null) { response.Close(); } } } catch (WebException wex) { ProcessWebException(task, wex); } catch (AggregateException aex) { // Non-retryable error CompleteFailedTask(task, aex); } }); } catch (WebException wex) { ProcessWebException(task, wex); } catch (SecurityException sex) { // Non-retryable error CompleteFailedTask(task, sex); } }
public void Process(HttpListenerRequest request, HttpListenerResponse response) { try { if (request.HttpMethod != "PUT" && request.HttpMethod != "DELETE") { FinalizeRejectedResponse(request, response, 405, "Method Not Supported", null); return; } if (request.QueryString.Count < 2) { FinalizeRejectedResponse(request, response, 400, "Bad Request", null); return; } Guid?guid = RetrieveGuidParameter(request); if (!guid.HasValue) { FinalizeRejectedResponse(request, response, 400, "Bad Request", null); return; } Uri url = RetrieveUrlParameter(request); if (url == null) { FinalizeRejectedResponse(request, response, 400, "Bad Request", null); return; } if (UrlContainsDangerousMarkup(url)) { FinalizeRejectedResponse(request, response, 400, "Bad Request", url); return; } RevaleeUrlAuthorization authorization = Supervisor.Configuration.AuthorizedTargets.Match(url); if (authorization == null) { // Keep all authorization errors homogeneous from the client perspective RevaleeUrlAuthorization.ObfuscateExecutionTime(); FinalizeRejectedResponse(request, response, 401, "Unauthorized", url); return; } if (!authorization.IsAuthorizedRequestSource(request.RemoteEndPoint.Address)) { // Keep all authorization errors homogeneous from the client perspective RevaleeUrlAuthorization.ObfuscateExecutionTime(); FinalizeRejectedResponse(request, response, 401, "Unauthorized", url); return; } if (Supervisor.Work.IsOverloaded) { FinalizeRejectedResponse(request, response, 503, "Service Unavailable", url); return; } RevaleeTask taskToCancel = RevaleeTask.Revive(DateTime.MinValue, url, DateTime.UtcNow, guid.Value, 0, null); Supervisor.State.CancelTask(taskToCancel); FinalizeAcceptedResponse(request, response, guid.Value, url); return; } catch (HttpListenerException hlex) { Supervisor.LogException(hlex, TraceEventType.Error, request.RawUrl); FinalizeRejectedResponse(request, response, 500, "Error Occurred", null); return; } }
public void Process(HttpListenerRequest request, HttpListenerResponse response) { try { if (request.HttpMethod != "PUT") { FinalizeRejectedResponse(request, response, 405, "Method Not Supported", null); return; } if (request.QueryString.Count < 2) { FinalizeRejectedResponse(request, response, 400, "Bad Request", null); return; } Uri url = RetrieveUrlParameter(request); if (url == null) { FinalizeRejectedResponse(request, response, 400, "Bad Request", null); return; } DateTime?time = RetrieveTimeParameter(request); if (!time.HasValue) { FinalizeRejectedResponse(request, response, 400, "Bad Request", url); return; } if (UrlContainsDangerousMarkup(url)) { FinalizeRejectedResponse(request, response, 400, "Bad Request", url); return; } RevaleeUrlAuthorization authorization = Supervisor.Configuration.AuthorizedTargets.Match(url); if (authorization == null) { // Keep all authorization errors homogeneous from the client perspective RevaleeUrlAuthorization.ObfuscateExecutionTime(); FinalizeRejectedResponse(request, response, 401, "Unauthorized", url); return; } if (!authorization.IsAuthorizedRequestSource(request.RemoteEndPoint.Address)) { // Keep all authorization errors homogeneous from the client perspective RevaleeUrlAuthorization.ObfuscateExecutionTime(); FinalizeRejectedResponse(request, response, 401, "Unauthorized", url); return; } if (Supervisor.Work.IsOverloaded) { FinalizeRejectedResponse(request, response, 503, "Service Unavailable", url); return; } string authorizationCipher = RetrieveAuthorizationHeader(request); RevaleeTask newTask = new RevaleeTask(time.Value, url, authorization.RetryCount, authorizationCipher); Supervisor.State.AddTask(newTask); FinalizeAcceptedResponse(request, response, newTask); return; } catch (HttpListenerException hlex) { Supervisor.LogException(hlex, TraceEventType.Error, request.RawUrl); FinalizeRejectedResponse(request, response, 500, "Error Occurred", null); return; } }
private static string FormatGenericExceptionMessage(RevaleeTask task, Exception exception) { return(string.Format("{0} [{1}]", exception.Message, task.CallbackUrl.OriginalString)); }
private static string FormatWebExceptionMessage(RevaleeTask task, WebException webException) { return(string.Format("Unsuccessful callback to {0} with status '{1}'. [{2}]", task.CallbackUrl.OriginalString, webException.Status.ToString(), task.CallbackId)); }
private static void FinalizeAcceptedResponse(HttpListenerRequest request, HttpListenerResponse response, RevaleeTask task) { string remoteAddress = request.RemoteEndPoint.Address.ToString(); try { response.StatusCode = 200; response.StatusDescription = "OK"; byte[] confirmation_number = Encoding.UTF8.GetBytes(task.CallbackId.ToString()); response.ContentLength64 = confirmation_number.LongLength; response.OutputStream.Write(confirmation_number, 0, confirmation_number.Length); } finally { response.Close(); } Supervisor.Telemetry.RecordAcceptedRequest(); Supervisor.LogEvent(string.Format("Request accepted for {0} @ {1:d} {1:t} from {2}. [{3}]", task.CallbackUrl.OriginalString, task.CallbackTime, remoteAddress, task.CallbackId), TraceEventType.Verbose); }