/// <summary> /// Overridden to send job to job processor /// </summary> /// <param name="resourceDescriptor"></param> /// <param name="resource"></param> /// <returns></returns> public override async Task<Job> Create(ResourceDescriptor resourceDescriptor, Job resource) { resource.JobStatus = "New"; // create the job var job = await base.Create(resourceDescriptor, resource); // get all services var services = await DataHandler.Query<Service>(ResourceDescriptor.FromUrl<Service>(Environment.ServiceRegistryServicesUrl())); // find first service that has a job processing endpoint var serviceResource = services .SelectMany(s => s.HasResource.Select(r => new {Service = s, Resource = r})) .FirstOrDefault( sr => sr.Resource.ResourceType == nameof(JobProcess) && !string.IsNullOrWhiteSpace(sr.Resource.HttpEndpoint)); if (serviceResource == null) { job.JobStatusReason = "No JobProcessor endpoints registered in the service registry."; job.JobStatus = "Failed"; return await Update(resourceDescriptor, job); } try { // gets the authorized url var url = AuthorizedUrlBuilder.GetAuthorizedUrl(serviceResource.Resource); // send the job to the job processing endpoint await DataHandler.Create(ResourceDescriptor.FromUrl<JobProcess>(url), new JobProcess {Job = job}); return await Get(resourceDescriptor); } catch (Exception ex) { job.JobStatusReason = $"Failed to send job to JobProcessor endpoint {serviceResource.Resource.HttpEndpoint}: {ex}"; job.JobStatus = "Failed"; return await Update(resourceDescriptor, job); } }
/// <summary> /// Handles creation of a job /// </summary> /// <param name="resourceDescriptor"></param> /// <param name="jobProcess"></param> /// <returns></returns> public override async Task <JobProcess> Create(ResourceDescriptor resourceDescriptor, JobProcess jobProcess) { // ensure status is set to New jobProcess.JobProcessStatus = "New"; // call base first jobProcess = await base.Create(resourceDescriptor, jobProcess); // retrieve the job data var job = await DataHandler.Get <Job>(jobProcess.Job.Id); if (job != null) { // validate the job before processing job.Validate(); // set the job process ID job.JobProcess = jobProcess.Id; // get all services var services = await DataHandler.Query <Service>(ResourceDescriptor.FromUrl <Service>(Environment.ServiceRegistryServicesUrl())); // find first service that can accept the job type and that has a job assignment endpoint var serviceResource = services .Where(s => s.CanAcceptJob(job)) .SelectMany(s => s.HasResource.Select(r => new { Service = s, Resource = r })) .FirstOrDefault( sr => sr.Resource.ResourceType == nameof(JobAssignment) && !string.IsNullOrWhiteSpace(sr.Resource.HttpEndpoint)); // check that we found an acceptable endpoint if (serviceResource != null) { try { // gets the authorized url var authorizedUrl = AuthorizedUrlBuilder.GetAuthorizedUrl(serviceResource.Resource); // send the job to the job assignment endpoint var jobAssignment = await DataHandler.Create(ResourceDescriptor.FromUrl <JobAssignment>(authorizedUrl), new JobAssignment { JobProcess = jobProcess.Id }); // set assignment back on the job process jobProcess.JobAssignment = jobAssignment.Id; // set status to Running jobProcess.JobProcessStatus = job.JobStatus = "Running"; jobProcess.JobStart = DateTime.UtcNow; } catch (Exception ex) { Logger.Error("Service '{0}' at {1} failed to accept JobAssignment. Exception: {2}", serviceResource.Service.Label, serviceResource.Resource.HttpEndpoint, ex); job.JobStatus = jobProcess.JobProcessStatus = "Failed"; job.JobStatusReason = jobProcess.JobProcessStatusReason = $"Service '{serviceResource.Service.Label}' at {serviceResource.Resource.HttpEndpoint} failed to accept JobAssignment. Exception: {ex}"; } } else { Logger.Warning("No accepting service available for job type {0}.", job.Type); job.JobStatus = jobProcess.JobProcessStatus = "Failed"; job.JobStatusReason = jobProcess.JobProcessStatusReason = $"No accepting service available for job type {job.Type}."; } // update the job try { await DataHandler.Update(job); } catch (Exception ex) { Logger.Error("Unable to update job {0}. Exception: {1}", job.Id, ex); jobProcess.JobProcessStatus = "Failed"; jobProcess.JobProcessStatusReason = $"Unable to update job {job.Id}. Exception: {ex}"; } // hit the async callback endpoint if (jobProcess.JobProcessStatus == "Failed" && job.AsyncEndpoint != null && !string.IsNullOrWhiteSpace(job.AsyncEndpoint.AsyncFailure)) { await DataHandler.Get <Resource>(job.AsyncEndpoint.AsyncFailure); } } else { jobProcess.JobProcessStatus = "Failed"; jobProcess.JobProcessStatusReason = $"Unable to retrieve job '{jobProcess.Job}'"; } // update the JobProcess record and return it return(await Update(resourceDescriptor, jobProcess)); }
/// <summary> /// Updates a resource /// </summary> /// <typeparam name="T"></typeparam> /// <param name="resourceDataHandler"></param> /// <param name="resource"></param> /// <returns></returns> public static Task <T> Update <T>(this IResourceDataHandler resourceDataHandler, T resource) where T : Resource, new() { return(resourceDataHandler.Update(ResourceDescriptor.FromUrl <T>(resource.Id), resource)); }
/// <summary> /// Gets a resource by its url /// </summary> /// <typeparam name="T"></typeparam> /// <param name="resourceDataHandler"></param> /// <param name="url"></param> /// <returns></returns> public static Task <Resource> Get(this IResourceDataHandler resourceDataHandler, string url) { return(resourceDataHandler.Get(ResourceDescriptor.FromUrl <Resource>(url))); }
/// <summary> /// Gets a resource by its url /// </summary> /// <typeparam name="T"></typeparam> /// <param name="resourceDataHandler"></param> /// <param name="url"></param> /// <returns></returns> public static Task <T> Get <T>(this IResourceDataHandler resourceDataHandler, string url) where T : Resource, new() { return(resourceDataHandler.Get <T>(ResourceDescriptor.FromUrl <T>(url))); }