PageRenderTime 39ms CodeModel.GetById 18ms RepoModel.GetById 0ms app.codeStats 0ms

/src/NuGet.Services.Work/WorkService.cs

https://github.com/ewilde/NuGet.Services.Work
C# | 194 lines | 161 code | 23 blank | 10 comment | 6 complexity | 562321dfe1944c5aecdef3f56b4306b1 MD5 | raw file
Possible License(s): Apache-2.0
  1. using System;
  2. using System.Reactive.Linq;
  3. using System.Collections.Generic;
  4. using System.Diagnostics.Tracing;
  5. using System.IO;
  6. using System.Linq;
  7. using System.Text;
  8. using System.Threading.Tasks;
  9. using Microsoft.Practices.EnterpriseLibrary.SemanticLogging;
  10. using Microsoft.Practices.EnterpriseLibrary.SemanticLogging.Formatters;
  11. using Microsoft.Practices.EnterpriseLibrary.SemanticLogging.Sinks;
  12. using Microsoft.WindowsAzure.Diagnostics;
  13. using Microsoft.WindowsAzure.ServiceRuntime;
  14. using Microsoft.WindowsAzure.Storage;
  15. using Microsoft.WindowsAzure.Storage.Table;
  16. using System.Reactive.Subjects;
  17. using System.Reactive.Disposables;
  18. using Microsoft.WindowsAzure.Storage.Blob;
  19. using NuGet.Services.Work.Monitoring;
  20. using System.Net;
  21. using NuGet.Services.Storage;
  22. using NuGet.Services.Work.Configuration;
  23. using Autofac.Core;
  24. using Autofac;
  25. using NuGet.Services.ServiceModel;
  26. using NuGet.Services.Work.Api.Models;
  27. using NuGet.Services.Configuration;
  28. using NuGet.Services.Work.Models;
  29. using System.Threading;
  30. using System.Diagnostics;
  31. using Autofac.Features.ResolveAnything;
  32. using NuGet.Services.Http;
  33. using Microsoft.Owin;
  34. using System.Web.Http.Routing;
  35. using NuGet.Services.Work.Azure;
  36. namespace NuGet.Services.Work
  37. {
  38. public class WorkService : NuGetApiService
  39. {
  40. internal const string InvocationLogsContainerBaseName = "ng-work-invocations";
  41. public static readonly int DefaultWorkersPerCore = 2;
  42. private static readonly PathString _basePath = new PathString("/work");
  43. private List<ILifetimeScope> _scopes = new List<ILifetimeScope>();
  44. public override PathString BasePath
  45. {
  46. get { return _basePath; }
  47. }
  48. public IEnumerable<JobDescription> Jobs { get; private set; }
  49. public IEnumerable<Worker> Workers { get; private set; }
  50. public int? MaxWorkers { get; protected set; }
  51. public int? WorkersPerCore { get; protected set; }
  52. protected InvocationQueue Queue { get; set; }
  53. public WorkService(ServiceName name, ServiceHost host)
  54. : base(name, host)
  55. {
  56. var workConfig = host.Config.GetSection<WorkConfiguration>();
  57. MaxWorkers = MaxWorkers ?? workConfig.MaxWorkers;
  58. WorkersPerCore = WorkersPerCore ?? (workConfig.WorkersPerCore ?? DefaultWorkersPerCore);
  59. }
  60. protected override async Task<bool> OnStart()
  61. {
  62. try
  63. {
  64. // Discover jobs
  65. DiscoverJobs();
  66. // Determine how many workers to create
  67. Debug.Assert(WorkersPerCore.HasValue); // Constructor should have set a default value
  68. int workerCount = WorkersPerCore.Value * Environment.ProcessorCount;
  69. if (MaxWorkers != null)
  70. {
  71. workerCount = Math.Min(workerCount, MaxWorkers.Value);
  72. }
  73. // Create the workers
  74. Workers = Enumerable.Range(0, workerCount).Select(CreateWorker);
  75. return await base.OnStart();
  76. }
  77. catch (Exception ex)
  78. {
  79. // Exceptions that escape to this level are fatal
  80. WorkServiceEventSource.Log.StartupError(ex);
  81. return false;
  82. }
  83. }
  84. protected override Task OnRun()
  85. {
  86. return Task.WhenAll(Workers.Select(w => w.StartAndRun(Host.ShutdownToken)));
  87. }
  88. protected override void OnShutdown()
  89. {
  90. foreach (var scope in _scopes)
  91. {
  92. scope.Dispose();
  93. }
  94. }
  95. private Worker CreateWorker(int id)
  96. {
  97. // Create a scope for this worker
  98. var scope = Container.BeginLifetimeScope(builder =>
  99. {
  100. // Register components
  101. builder.RegisterModule(
  102. new JobComponentsModule(
  103. ServiceName.ToString() + "#" + id.ToString(),
  104. Queue));
  105. // Register the worker
  106. builder
  107. .RegisterType<Worker>()
  108. .WithParameter(new NamedParameter("id", id))
  109. .AsSelf()
  110. .SingleInstance();
  111. });
  112. _scopes.Add(scope);
  113. return scope.Resolve<Worker>();
  114. }
  115. private void DiscoverJobs()
  116. {
  117. Jobs = Container.Resolve<IEnumerable<JobDescription>>();
  118. foreach (var job in Jobs)
  119. {
  120. // Record the discovery in the trace
  121. WorkServiceEventSource.Log.JobDiscovered(job);
  122. }
  123. }
  124. public override void RegisterComponents(ContainerBuilder builder)
  125. {
  126. base.RegisterComponents(builder);
  127. var jobdefs = GetAllAvailableJobs();
  128. builder.RegisterInstance(jobdefs).As<IEnumerable<JobDescription>>();
  129. // Register an invocation queue for the API to use. The workers will register
  130. // their own in a sub scope
  131. if (Queue == null)
  132. {
  133. builder
  134. .RegisterType<InvocationQueue>()
  135. .AsSelf()
  136. .UsingConstructor(
  137. typeof(Clock),
  138. typeof(string),
  139. typeof(StorageHub),
  140. typeof(ConfigurationHub))
  141. .WithParameter(
  142. new NamedParameter("instanceName", ServiceName.ToString() + "#api"));
  143. }
  144. else
  145. {
  146. builder.RegisterInstance(Queue).As<InvocationQueue>();
  147. }
  148. }
  149. public static IEnumerable<JobDescription> GetAllAvailableJobs()
  150. {
  151. var jobdefs = typeof(WorkService)
  152. .Assembly
  153. .GetExportedTypes()
  154. .Where(t => !t.IsAbstract && typeof(JobHandlerBase).IsAssignableFrom(t))
  155. .Select(t => JobDescription.Create(t))
  156. .Where(d => d != null);
  157. return jobdefs;
  158. }
  159. public override async Task<object> GetCurrentStatus()
  160. {
  161. return (await Task.WhenAll(Workers.Select(async w => Tuple.Create(w.Id, await w.GetCurrentStatus())))).ToDictionary(
  162. t => ServiceName.ToString() + "#" + t.Item1.ToString(),
  163. t => t.Item2);
  164. }
  165. protected override void ConfigureAttributeRouting(DefaultInlineConstraintResolver resolver)
  166. {
  167. base.ConfigureAttributeRouting(resolver);
  168. resolver.ConstraintMap.Add("invocationListCriteria", typeof(EnumConstraint<InvocationListCriteria>));
  169. }
  170. }
  171. }