Esempio n. 1
0
        private async Task <bool> ExecuteAsync()
        {
            string joinCharacter = ApiEndpoint.Contains("?") ? "&" : "?";
            string apiUrl        = ApiEndpoint + joinCharacter + "access_token=" + Uri.EscapeDataString(AccessToken);

            Log.LogMessage(MessageImportance.Low, "Posting job to {0}", ApiEndpoint);
            Log.LogMessage(MessageImportance.Low, "Event json is ", EventDataPath);

            using (HttpClient client = new HttpClient())
            {
                int retryCount = 15;
                while (true)
                {
                    HttpResponseMessage response;

                    using (Stream stream = File.OpenRead(EventDataPath))
                    {
                        HttpContent contentStream = new StreamContent(stream);
                        contentStream.Headers.Add("Content-Type", "application/json");
                        response = await client.PostAsync(apiUrl, contentStream);
                    }

                    if (response.IsSuccessStatusCode)
                    {
                        JObject responseObject;
                        using (Stream stream = await response.Content.ReadAsStreamAsync())
                            using (StreamReader streamReader = new StreamReader(stream))
                                using (JsonReader jsonReader = new JsonTextReader(streamReader))
                                {
                                    responseObject = JObject.Load(jsonReader);
                                }

                        JobId = (string)responseObject["Name"];
                        if (String.IsNullOrEmpty(JobId))
                        {
                            Log.LogError("Publish to '{0}' did not return a job ID", ApiEndpoint);
                            return(false);
                        }

                        Log.LogMessage(MessageImportance.High, "Started Helix job: CorrelationId = {0}", JobId);
                        return(true);
                    }

                    if (retryCount-- <= 0)
                    {
                        Log.LogError(
                            "Unable to publish to '{0}' after 15 retries. Received status code: {1} {2}",
                            ApiEndpoint,
                            response.StatusCode,
                            response.ReasonPhrase);
                        return(false);
                    }

                    Log.LogWarning("Failed to publish to '{0}', {1} retries remaining", ApiEndpoint, retryCount);
                }
            }
        }
Esempio n. 2
0
        private async Task <bool> ExecuteAsync()
        {
            List <ITaskItem> jobIds        = new List <ITaskItem>();
            string           joinCharacter = ApiEndpoint.Contains("?") ? "&" : "?";
            string           apiUrl        = ApiEndpoint + joinCharacter + "access_token=" + Uri.EscapeDataString(AccessToken);

            Log.LogMessage(MessageImportance.Normal, "Posting job to {0}", ApiEndpoint);
            Log.LogMessage(MessageImportance.Low, "Using Job Event json from ", EventDataPath);

            string buildJsonText = File.ReadAllText(EventDataPath);

            List <JObject> allBuilds = new List <JObject>();

            try
            {
                allBuilds.AddRange(JsonConvert.DeserializeObject <List <JObject> >(buildJsonText));
            }
            catch (JsonSerializationException)
            {
                // If this fails, we'll let it tear us down.
                // Since if this isn't even valid JSON there's no use posting it.
                allBuilds.Add(JsonConvert.DeserializeObject <JObject>(buildJsonText));
            }

            using (HttpClient client = new HttpClient())
            {
                const int MaxAttempts = 15;
                // add a bit of randomness to the retry delay
                var rng        = new Random();
                int retryCount = MaxAttempts;

                foreach (JObject jobStartMessage in allBuilds)
                {
                    string queueId = (string)jobStartMessage["QueueId"];
                    // This should never happen.
                    if (string.IsNullOrEmpty(queueId))
                    {
                        Log.LogError("Helix Job Start messages must have a value for 'QueueId' ");
                    }
                    bool keepTrying = true;
                    while (keepTrying)
                    {
                        HttpResponseMessage response = new HttpResponseMessage();

                        try
                        {
                            // This tortured way to get the HTTPContent is to work around that StringContent doesn't allow application/json
                            HttpContent contentStream = new StreamContent(new MemoryStream(Encoding.UTF8.GetBytes(jobStartMessage.ToString())));
                            contentStream.Headers.Add("Content-Type", "application/json");
                            response = await client.PostAsync(apiUrl, contentStream);

                            if (response.IsSuccessStatusCode)
                            {
                                JObject responseObject = new JObject();
                                using (Stream stream = await response.Content.ReadAsStreamAsync())
                                    using (StreamReader streamReader = new StreamReader(stream))
                                    {
                                        string jsonResponse = streamReader.ReadToEnd();
                                        try
                                        {
                                            using (JsonReader jsonReader = new JsonTextReader(new StringReader(jsonResponse)))
                                            {
                                                responseObject = JObject.Load(jsonReader);
                                            }
                                        }
                                        catch
                                        {
                                            Log.LogWarning($"Hit exception attempting to parse JSON response.  Raw response string: {Environment.NewLine} {jsonResponse}");
                                        }
                                    }

                                string jobId = (string)responseObject["Name"];
                                if (String.IsNullOrEmpty(jobId))
                                {
                                    Log.LogError("Publish to '{0}' did not return a job ID", ApiEndpoint);
                                }
                                TaskItem helixJobStartedInfo = new TaskItem(jobId);
                                helixJobStartedInfo.SetMetadata("CorrelationId", jobId);
                                helixJobStartedInfo.SetMetadata("QueueId", queueId);
                                helixJobStartedInfo.SetMetadata("QueueTimeUtc", DateTime.UtcNow.ToString());
                                jobIds.Add(helixJobStartedInfo);

                                Log.LogMessage(MessageImportance.High, "Started Helix job: CorrelationId = {0}", jobId);
                                keepTrying = false;
                            }
                            else
                            {
                                string responseContent = await response.Content.ReadAsStringAsync();

                                Log.LogWarning($"Helix Api Response: StatusCode {response.StatusCode} {responseContent}");
                            }
                        }
                        // still allow other types of exceptions to tear down the task for now
                        catch (HttpRequestException toLog)
                        {
                            Log.LogWarning("Exception thrown attempting to submit job to Helix:");
                            Log.LogWarningFromException(toLog, true);
                        }

                        if (retryCount-- <= 0)
                        {
                            Log.LogError($"Unable to publish to '{ApiEndpoint}' after {MaxAttempts} retries. Received status code: {response.StatusCode} {response.ReasonPhrase}");
                            keepTrying = false;
                        }
                        if (keepTrying)
                        {
                            Log.LogWarning("Failed to publish to '{0}', {1} retries remaining", ApiEndpoint, retryCount);
                            int delay = (MaxAttempts - retryCount) * rng.Next(1, 7);
                            await System.Threading.Tasks.Task.Delay(delay * 1000);
                        }
                    }
                }
                JobIds = jobIds.ToArray();
                // Number of queued builds = number in that file == success.
                return(allBuilds.Count == jobIds.Count);
            }
        }
Esempio n. 3
0
        private async Task <bool> ExecuteAsync()
        {
            string joinCharacter = ApiEndpoint.Contains("?") ? "&" : "?";
            string apiUrl        = ApiEndpoint + joinCharacter + "access_token=" + Uri.EscapeDataString(AccessToken);

            Log.LogMessage(MessageImportance.Low, "Posting job to {0}", ApiEndpoint);
            Log.LogMessage(MessageImportance.Low, "Event json is ", EventDataPath);

            using (HttpClient client = new HttpClient())
            {
                const int MaxAttempts = 15;
                // add a bit of randomness to the retry delay
                var rng        = new Random();
                int retryCount = MaxAttempts;

                while (true)
                {
                    HttpResponseMessage response = new HttpResponseMessage();

                    try
                    {
                        using (Stream stream = File.OpenRead(EventDataPath))
                        {
                            HttpContent contentStream = new StreamContent(stream);
                            contentStream.Headers.Add("Content-Type", "application/json");
                            response = await client.PostAsync(apiUrl, contentStream);
                        }

                        if (response.IsSuccessStatusCode)
                        {
                            JObject responseObject;
                            using (Stream stream = await response.Content.ReadAsStreamAsync())
                                using (StreamReader streamReader = new StreamReader(stream))
                                    using (JsonReader jsonReader = new JsonTextReader(streamReader))
                                    {
                                        responseObject = JObject.Load(jsonReader);
                                    }

                            JobId = (string)responseObject["Name"];
                            if (String.IsNullOrEmpty(JobId))
                            {
                                Log.LogError("Publish to '{0}' did not return a job ID", ApiEndpoint);
                                return(false);
                            }

                            Log.LogMessage(MessageImportance.High, "Started Helix job: CorrelationId = {0}", JobId);
                            return(true);
                        }
                        else
                        {
                            string responseContent = await response.Content.ReadAsStringAsync();

                            Log.LogWarning($"Helix Api Response: StatusCode {response.StatusCode} {responseContent}");
                        }
                    }
                    // still allow other types of exceptions to tear down the task for now
                    catch (HttpRequestException toLog)
                    {
                        Log.LogWarning("Exception thrown attempting to submit job to Helix:");
                        Log.LogWarningFromException(toLog, true);
                    }

                    if (retryCount-- <= 0)
                    {
                        Log.LogError($"Unable to publish to '{ApiEndpoint}' after {MaxAttempts} retries. Received status code: {response.StatusCode} {response.ReasonPhrase}");
                        return(false);
                    }

                    Log.LogWarning("Failed to publish to '{0}', {1} retries remaining", ApiEndpoint, retryCount);
                    int delay = (MaxAttempts - retryCount) * rng.Next(1, 7);
                    await System.Threading.Tasks.Task.Delay(delay * 1000);
                }
            }
        }
Esempio n. 4
0
        private async Task <bool> ExecuteAsync()
        {
            List <ITaskItem> jobIds = new List <ITaskItem>();
            string           apiUrl = ApiEndpoint;

            if (!String.IsNullOrEmpty(AccessToken))
            {
                string joinCharacter = ApiEndpoint.Contains("?") ? "&" : "?";
                apiUrl = ApiEndpoint + joinCharacter + "access_token=" + Uri.EscapeDataString(AccessToken);
            }

            Log.LogMessage(MessageImportance.Normal, "Posting job to {0}", ApiEndpoint);
            Log.LogMessage(MessageImportance.Low, "Using Job Event json from ", EventDataPath);

            string buildJsonText = File.ReadAllText(EventDataPath);

            List <JObject> allBuilds = new List <JObject>();

            try
            {
                allBuilds.AddRange(JsonConvert.DeserializeObject <List <JObject> >(buildJsonText));
            }
            catch (JsonSerializationException)
            {
                // If this fails, we'll let it tear us down.
                // Since if this isn't even valid JSON there's no use posting it.
                allBuilds.Add(JsonConvert.DeserializeObject <JObject>(buildJsonText));
            }

            using (HttpClient client = new HttpClient()
            {
                Timeout = TimeSpan.FromSeconds(30) // Default is 100 seconds.  15 timeouts @ 30 seconds = ~7:30
            })
            {
                const int MaxAttempts = 15;
                // add a bit of randomness to the retry delay
                var rng = new Random();

                // We'll use this to be sure TaskCancelledException comes from timeouts
                CancellationTokenSource cancelTokenSource = new CancellationTokenSource();

                foreach (JObject jobStartMessage in allBuilds)
                {
                    int    retryCount = MaxAttempts;
                    bool   keepTrying = true;
                    string queueId    = (string)jobStartMessage["QueueId"];
                    if (string.IsNullOrEmpty(queueId))
                    {
                        Log.LogError("Helix Job Start messages must have a value for 'QueueId' ");
                        keepTrying = false; // this will fail in the API, so we won't even try.
                    }
                    // Provides a way for the API to realize that a given job has been recently queued
                    // which allows us to retry in the case of ambiguous results such as HttpClient timeout.
                    string jobStartIdentifier = Guid.NewGuid().ToString("N");
                    jobStartMessage["JobStartIdentifier"] = jobStartIdentifier;
                    Log.LogMessage(MessageImportance.Low, $"Sending job start with identifier '{jobStartIdentifier}'");

                    while (keepTrying)
                    {
                        HttpResponseMessage response = new HttpResponseMessage();
                        try
                        {
                            // This workaround to get the HTTPContent is to work around that StringContent doesn't allow application/json
                            HttpContent contentStream = new StreamContent(new MemoryStream(Encoding.UTF8.GetBytes(jobStartMessage.ToString())));
                            contentStream.Headers.Add("Content-Type", "application/json");
                            response = await client.PostAsync(apiUrl, contentStream, cancelTokenSource.Token);

                            if (response.IsSuccessStatusCode)
                            {
                                JObject responseObject = new JObject();
                                using (Stream stream = await response.Content.ReadAsStreamAsync())
                                    using (StreamReader streamReader = new StreamReader(stream))
                                    {
                                        string jsonResponse = streamReader.ReadToEnd();
                                        try
                                        {
                                            using (JsonReader jsonReader = new JsonTextReader(new StringReader(jsonResponse)))
                                            {
                                                responseObject = JObject.Load(jsonReader);
                                            }
                                        }
                                        catch
                                        {
                                            Log.LogWarning($"Hit exception attempting to parse JSON response.  Raw response string: {Environment.NewLine} {jsonResponse}");
                                        }
                                    }

                                string jobId = (string)responseObject["Name"];
                                if (String.IsNullOrEmpty(jobId))
                                {
                                    Log.LogError("Publish to '{0}' did not return a job ID", ApiEndpoint);
                                }
                                TaskItem helixJobStartedInfo = new TaskItem(jobId);
                                helixJobStartedInfo.SetMetadata("CorrelationId", jobId);
                                helixJobStartedInfo.SetMetadata("QueueId", queueId);
                                helixJobStartedInfo.SetMetadata("QueueTimeUtc", DateTime.UtcNow.ToString());
                                jobIds.Add(helixJobStartedInfo);

                                Log.LogMessage(MessageImportance.High, "Started Helix job: CorrelationId = {0}", jobId);
                                keepTrying = false;
                            }
                            else
                            {
                                string responseContent = await response.Content.ReadAsStringAsync();

                                Log.LogWarning($"Helix Api Response: StatusCode {response.StatusCode} {responseContent}");
                            }
                        }
                        // still allow other types of exceptions to tear down the task for now
                        catch (HttpRequestException toLog)
                        {
                            Log.LogWarning("Exception thrown attempting to submit job to Helix:");
                            Log.LogWarningFromException(toLog, true);
                        }
                        catch (TaskCanceledException possibleClientTimeout)
                        {
                            if (possibleClientTimeout.CancellationToken != cancelTokenSource.Token)
                            {
                                // This is a timeout.  Since we provided a JobIdentifier value, we can retry.
                                Log.LogWarning($"HttpClient timeout while attempting to POST new job to '{queueId}', will retry. Job Start Identifier: {jobStartIdentifier}");
                            }
                            else
                            {
                                // Something else caused cancel, throw it.  Should not ever get here.
                                throw;
                            }
                        }
                        if (retryCount-- <= 0)
                        {
                            Log.LogError($"Unable to publish to '{ApiEndpoint}' after {MaxAttempts} retries. Received status code: {response.StatusCode} {response.ReasonPhrase}");
                            keepTrying = false;
                        }
                        if (keepTrying)
                        {
                            Log.LogWarning("Failed to publish to '{0}', {1} retries remaining", ApiEndpoint, retryCount);
                            int delay = (MaxAttempts - retryCount) * rng.Next(1, 7);
                            await System.Threading.Tasks.Task.Delay(delay * 1000);
                        }
                    }
                }
                JobIds = jobIds.ToArray();
                // Number of queued builds = number in that file == success.
                // If any timeouts or other failures occur this will cause the task to fail.
                return(allBuilds.Count == jobIds.Count);
            }
        }