{"id":348601,"date":"2023-06-10T03:00:57","date_gmt":"2023-06-10T03:00:57","guid":{"rendered":"http:\/\/savepearlharbor.com\/?p=348601"},"modified":"-0001-11-30T00:00:00","modified_gmt":"-0001-11-29T21:00:00","slug":"","status":"publish","type":"post","link":"https:\/\/savepearlharbor.com\/?p=348601","title":{"rendered":"<span>\u0421\u043e\u0437\u0434\u0430\u043d\u0438\u0435 \u0444\u043e\u043d\u043e\u0432\u044b\u0445 \u0437\u0430\u0434\u0430\u0447 \u0432 .NET \u0441 \u0437\u0430\u043f\u0440\u043e\u0441\u043e\u043c \u0441\u043e\u0441\u0442\u043e\u044f\u043d\u0438\u044f \u0437\u0430\u043f\u0443\u0449\u0435\u043d\u043d\u043e\u0433\u043e \u0442\u0430\u0441\u043a\u0430<\/span>"},"content":{"rendered":"<div><\/div>\n<div id=\"post-content-body\">\n<div>\n<div class=\"article-formatted-body article-formatted-body article-formatted-body_version-2\">\n<div xmlns=\"http:\/\/www.w3.org\/1999\/xhtml\">\n<p>\u0414\u043e\u043f\u0443\u0441\u0442\u0438\u043c, \u043d\u0435\u043e\u0431\u0445\u043e\u0434\u0438\u043c\u043e \u0437\u0430\u043f\u0443\u0441\u0442\u0438\u0442\u044c \u043c\u043d\u043e\u0436\u0435\u0441\u0442\u0432\u043e \u0444\u043e\u043d\u043e\u0432\u044b\u0445 \u0437\u0430\u0434\u0430\u0447 \u0432 .Net \u0441 \u0432\u043e\u0437\u043c\u043e\u0436\u043d\u043e\u0441\u0442\u044c\u044e \u0432 \u0434\u0430\u043b\u044c\u043d\u0435\u0439\u0448\u0435\u043c \u043e\u0431\u0440\u0430\u0442\u0438\u0442\u044c\u0441\u044f \u043a \u0438\u0445 \u0441\u043e\u0441\u0442\u043e\u044f\u043d\u0438\u044e. \u041e\u0431\u0440\u0430\u0449\u0435\u043d\u0438\u0435 \u043a \u0447\u043b\u0435\u043d\u0430\u043c \u043a\u043b\u0430\u0441\u0441\u0430 \u0437\u0430\u043f\u0443\u0449\u0435\u043d\u043d\u043e\u0439 \u0437\u0430\u0434\u0430\u0447\u0438 \u043c\u043e\u0436\u0435\u0442 \u0431\u044b\u0442\u044c \u043f\u043e\u043b\u0435\u0437\u043d\u043e, \u0435\u0441\u043b\u0438 \u043d\u0435\u043e\u0431\u0445\u043e\u0434\u0438\u043c\u043e \u043e\u0434\u043d\u043e\u0437\u043d\u0430\u0447\u043d\u043e \u043e\u043f\u0440\u0435\u0434\u0435\u043b\u0438\u0442\u044c \u0442\u0435\u043a\u0443\u0449\u0435\u0435 \u0441\u043e\u0441\u0442\u043e\u044f\u043d\u0438\u0435 \u043e\u0431\u044a\u0435\u043a\u0442\u0430 \u0432 \u043c\u043e\u043c\u0435\u043d\u0442 \u0432\u044b\u043f\u043e\u043b\u043d\u0435\u043d\u0438\u044f.  <\/p>\n<h2>\u041e\u0434\u043d\u043e \u0438\u0437 \u0447\u0430\u0441\u0442\u043d\u044b\u0445 \u0440\u0435\u0448\u0435\u043d\u0438\u0439 \u2014 \u043c\u043e\u0434\u0435\u043b\u044c \u0430\u043a\u0442\u043e\u0440\u043e\u0432<\/h2>\n<p>\u041c\u043e\u0434\u0435\u043b\u044c \u0430\u043a\u0442\u043e\u0440\u043e\u0432 \u043f\u043e\u0437\u0432\u043e\u043b\u044f\u0435\u0442 \u0437\u0430\u043f\u0443\u0441\u043a\u0430\u0442\u044c  \u0444\u043e\u043d\u043e\u0432\u044b\u0435 \u0437\u0430\u0434\u0430\u0447\u0438 \u0438 \u043e\u0431\u0440\u0430\u0449\u0430\u0442\u044c\u0441\u044f \u043a \u0438\u0445 \u0442\u0435\u043a\u0443\u0449\u0435\u043c\u0443 \u0441\u043e\u0441\u0442\u043e\u044f\u043d\u0438\u044e.  <\/p>\n<h2>\u0418\u043d\u0442\u0435\u0440\u0444\u0435\u0439\u0441\u044b<\/h2>\n<p>\u041e\u043f\u0440\u0435\u0434\u0435\u043b\u0438\u043c \u0438\u043d\u0442\u0435\u0440\u0444\u0435\u0439\u0441, \u043a\u043e\u0442\u043e\u0440\u044b\u0439 \u043e\u043f\u0438\u0448\u0435\u0442 \u0432\u044b\u043f\u043e\u043b\u043d\u044f\u0435\u043c\u0443\u044e \u0440\u0430\u0431\u043e\u0442\u0443 \u2014 <a href=\"https:\/\/github.com\/qquser\/Akka.Jobs\/blob\/master\/Akka.Jobs\/Interfaces\/IJob.cs\" rel=\"noopener noreferrer nofollow\">IJob<\/a>, \u0441 \u043e\u0431\u044f\u0437\u0430\u0442\u0435\u043b\u044c\u043d\u043e\u0439 \u043f\u0435\u0440\u0435\u0434\u0430\u0447\u0435\u0439 \u0432 \u043c\u0435\u0442\u043e\u0434  <code>DoAsync<\/code> &#8212; <code>CancellationToken token<\/code>.<\/p>\n<pre><code class=\"cs\">public interface IJob&lt;in TIn, out TOut>     where TIn : IJobInput     where TOut : IJobResult   {     Task&lt;bool> DoAsync(TIn input, CancellationToken token);      \/\/\/ &lt;summary>     \/\/\/ Describes the state of the fields of the IJob class that are changed by the DoAsync method.     \/\/\/ &lt;\/summary>     TOut GetCurrentState(Guid jobId); }<\/code><\/pre>\n<p>\u0418\u043d\u0442\u0435\u0440\u0444\u0435\u0439\u0441 \u0434\u0436\u043e\u0431\u0430 &#8212; <a href=\"https:\/\/github.com\/qquser\/Akka.Jobs\/blob\/master\/Akka.Jobs\/Interfaces\/IJob.cs\" rel=\"noopener noreferrer nofollow\">IJob<\/a> \u043e\u043f\u0440\u0435\u0434\u0435\u043b\u0435\u043d, \u043d\u043e \u0432\u044b\u0437\u043e\u0432 \u0435\u0433\u043e \u0438\u043c\u043f\u043b\u0435\u043c\u0435\u043d\u0442\u0430\u0446\u0438\u0438 \u043d\u0430\u043f\u0440\u044f\u043c\u0443\u044e \u043d\u0435 \u0434\u0430\u0441\u0442 \u0438\u0441\u043a\u043e\u043c\u044b\u0445 \u0440\u0435\u0437\u0443\u043b\u044c\u0442\u0430\u0442\u043e\u0432, \u043f\u043e\u044d\u0442\u043e\u043c\u0443 \u043d\u0435\u043e\u0431\u0445\u043e\u0434\u0438\u043c\u043e \u043e\u043f\u0440\u0435\u0434\u0435\u043b\u0438\u0442\u044c \u043a\u043e\u043d\u0442\u0435\u043a\u0441\u0442 \u0432\u044b\u043f\u043e\u043b\u043d\u0435\u043d\u0438\u044f \u0434\u0436\u043e\u0431\u043e\u0432  <a href=\"https:\/\/github.com\/qquser\/Akka.Jobs\/blob\/master\/Akka.Jobs\/Interfaces\/IJobContext.cs\" rel=\"noopener noreferrer nofollow\">IJobContext<\/a>, \u043a\u043e\u0442\u043e\u0440\u044b\u0439 \u043e\u0431\u044a\u0435\u0434\u0438\u043d\u0438\u0442 \u0433\u0440\u0443\u043f\u043f\u0443 \u0432\u044b\u043f\u043e\u043b\u043d\u044f\u0435\u043c\u044b\u0445 \u043e\u0434\u043d\u043e\u0442\u0438\u043f\u043d\u044b\u0445 \u0437\u0430\u0434\u0430\u0447. \u0417\u0434\u0435\u0441\u044c \u043d\u0435\u043e\u0431\u0445\u043e\u0434\u0438\u043c\u043e \u043f\u0440\u0435\u0434\u043e\u0441\u0442\u0430\u0432\u0438\u0442\u044c \u0432\u043e\u0437\u043c\u043e\u0436\u043d\u043e\u0441\u0442\u044c \u043d\u0435 \u0442\u043e\u043b\u044c\u043a\u043e \u0437\u0430\u043f\u0443\u0441\u043a\u0430\u0442\u044c \u0444\u043e\u043d\u043e\u0432\u044b\u0435 \u0442\u0430\u0441\u043a\u0438 <code>CreateJobAsync<\/code>, \u043d\u043e \u0438 \u043e\u0436\u0438\u0434\u0430\u0442\u044c \u043f\u043e\u043b\u043d\u043e\u0433\u043e \u0432\u044b\u043f\u043e\u043b\u043d\u0435\u043d\u0438\u044f \u0437\u0430\u0434\u0430\u0447\u0438 <code>DoJobAsync<\/code>.  <\/p>\n<pre><code class=\"cs\">public interface IJobContext&lt;in TIn, TOut>     where TIn : IJobInput     where TOut : IJobResult {      \/\/\/ &lt;summary>     \/\/\/ Create a background job     \/\/\/ &lt;\/summary>     \/\/\/ &lt;returns>Job Id&lt;\/returns>     Task&lt;JobCreatedCommandResult> CreateJobAsync(TIn input,         int? maxNrOfRetries = null,         TimeSpan? minBackoff = null,         TimeSpan? maxBackoff = null,           Guid? jobId = null,         TimeSpan? timeout = null);      \/\/\/ &lt;summary>     \/\/\/ Waiting for a response about the completion of the job     \/\/\/ &lt;\/summary>     Task&lt;JobDoneCommandResult> DoJobAsync(TIn input,         int? maxNrOfRetries = null, TimeSpan? minBackoff = null, TimeSpan? maxBackoff = null,  Guid? jobId = null, TimeSpan? timeout = null);      Task&lt;StopJobCommandResult> StopJobAsync(Guid jobId, TimeSpan? timeout = null);      Task&lt;IDictionary&lt;Guid, ReplyWorkerInfo&lt;TOut>>> GetAllJobsCurrentStatesAsync(long requestId, TimeSpan? timeout = null); }<\/code><\/pre>\n<h2>\u0420\u0435\u0430\u043b\u0438\u0437\u0430\u0446\u0438\u044f<\/h2>\n<p>\u041e\u0441\u043d\u043e\u0432\u043d\u043e\u0439 \u0438\u0434\u0435\u0435\u0439 \u043c\u043e\u0434\u0435\u043b\u0438 \u0430\u043a\u0442\u043e\u0440\u043e\u0432 \u044f\u0432\u043b\u044f\u0435\u0442\u0441\u044f \u0438\u0437\u043e\u043b\u044f\u0446\u0438\u044f \u0441\u043e\u0441\u0442\u043e\u044f\u043d\u0438\u044f \u043a\u0430\u0436\u0434\u043e\u0433\u043e \u043e\u0431\u044a\u0435\u043a\u0442\u0430 \u043c\u043e\u0434\u0435\u043b\u0438 \u043e\u0442 \u0432\u043d\u0435\u0448\u043d\u0435\u0433\u043e \u0432\u043c\u0435\u0448\u0430\u0442\u0435\u043b\u044c\u0441\u0442\u0432\u0430, \u0447\u0442\u043e \u0434\u043e\u043b\u0436\u043d\u043e \u0433\u0430\u0440\u0430\u043d\u0442\u0438\u0440\u043e\u0432\u0430\u0442\u044c \u043f\u0440\u0435\u0434\u0441\u043a\u0430\u0437\u0443\u0435\u043c\u043e\u0435 \u0438\u0437\u043c\u0435\u043d\u0435\u043d\u0438\u0435 \u0441\u0432\u043e\u0435\u0433\u043e \u0441\u043e\u0441\u0442\u043e\u044f\u043d\u0438\u044f. \u041e\u0431\u0449\u0435\u043d\u0438\u0435 \u043c\u0435\u0436\u0434\u0443 \u0430\u043a\u0442\u043e\u0440\u0430\u043c\u0438 \u043f\u0440\u043e\u0438\u0441\u0445\u043e\u0434\u0438\u0442 \u0447\u0435\u0440\u0435\u0437 \u043e\u0447\u0435\u0440\u0435\u0434\u0438 \u0441\u043e\u043e\u0431\u0449\u0435\u043d\u0438\u0439, \u0432 \u043a\u043e\u0442\u043e\u0440\u044b\u0435 \u0434\u043b\u044f \u043a\u0430\u0436\u0434\u043e\u0433\u043e \u0430\u043a\u0442\u043e\u0440\u0430 \u0443\u043f\u043e\u0440\u044f\u0434\u043e\u0447\u0438\u0432\u0430\u044e\u0442 \u0432\u0441\u0435 \u0432\u0445\u043e\u0434\u044f\u0449\u0438\u0435 \u0437\u0430\u043f\u0440\u043e\u0441\u044b, \u0447\u0442\u043e \u0434\u0430\u0435\u0442 \u043f\u043e\u0441\u043b\u0435\u0434\u043e\u0432\u0430\u0442\u0435\u043b\u044c\u043d\u043e\u0441\u0442\u044c \u0432\u044b\u043f\u043e\u043b\u043d\u0435\u043d\u0438\u044f \u043a\u043e\u043c\u0430\u043d\u0434 \u0438 \u0442\u0430\u043a\u0436\u0435 \u043f\u043e\u0437\u0432\u043e\u043b\u044f\u0435\u0442 \u0438\u0437\u0431\u0435\u0436\u0430\u0442\u044c \u043f\u043e\u0431\u043e\u0447\u043d\u044b\u0445 \u044d\u0444\u0444\u0435\u043a\u0442\u043e\u0432 \u0432\u043b\u0438\u044f\u043d\u0438\u044f \u043d\u0430 \u0447\u043b\u0435\u043d\u044b \u043a\u043b\u0430\u0441\u0441\u0430 \u0430\u043a\u0442\u043e\u0440\u0430.  <\/p>\n<p>\u041e\u0431\u0449\u0430\u044f \u0441\u0445\u0435\u043c\u0430 \u0437\u0430\u043f\u0440\u043e\u0441\u043e\u0432 \u0431\u0443\u0434\u0435\u0442 \u0432\u044b\u0433\u043b\u044f\u0434\u0435\u0442\u044c \u043a\u0430\u043a  <a href=\"https:\/\/github.com\/qquser\/Akka.Jobs\/blob\/master\/Akka.Jobs\/Theater\/Master\/MasterActor.cs\" rel=\"noopener noreferrer nofollow\">MasterActor<\/a>\u2192 <a href=\"https:\/\/github.com\/qquser\/Akka.Jobs\/blob\/master\/Akka.Jobs\/Theater\/Master\/Groups\/GroupActor.cs\" rel=\"noopener noreferrer nofollow\">GroupActor<\/a> \u2192 <a href=\"https:\/\/github.com\/qquser\/Akka.Jobs\/blob\/master\/Akka.Jobs\/Theater\/Master\/Groups\/Workers\/ManagerActor.cs\" rel=\"noopener noreferrer nofollow\">ManagerActor<\/a> \u2192 <a href=\"https:\/\/github.com\/qquser\/Akka.Jobs\/blob\/master\/Akka.Jobs\/Theater\/Master\/Groups\/Workers\/WorkerActor.cs\" rel=\"noopener noreferrer nofollow\">WorkerActor<\/a><\/p>\n<h2>MasterActor <\/h2>\n<p>\u041e\u043f\u0440\u0435\u0434\u0435\u043b\u0438\u043c \u0442\u043e\u0447\u043a\u0443 \u0432\u0445\u043e\u0434\u0430 \u0432 \u0441\u0438\u0441\u0442\u0435\u043c\u0443 \u0430\u043a\u0442\u043e\u0440\u043e\u0432 \u2014 \u044d\u0442\u043e \u0431\u0443\u0434\u0435\u0442 <a href=\"https:\/\/github.com\/qquser\/Akka.Jobs\/blob\/master\/Akka.Jobs\/Theater\/Master\/MasterActor.cs\" rel=\"noopener noreferrer nofollow\">MasterActor<\/a>.<\/p>\n<p>\u0415\u0433\u043e \u0437\u0430\u0434\u0430\u0447\u0430\u043c\u0438 \u044f\u0432\u043b\u044f\u0435\u0442\u0441\u044f \u0434\u043e\u0441\u0442\u0430\u0432\u043a\u0430 \u0441\u043e\u043e\u0431\u0449\u0435\u043d\u0438\u0439 \u0434\u043e \u0441\u0432\u043e\u0438\u0445 \u0434\u043e\u0447\u0435\u0440\u043d\u0438\u0445 \u0430\u043a\u0442\u043e\u0440\u043e\u0432 \u0438 \u043e\u043f\u0440\u0435\u0434\u0435\u043b\u0435\u043d\u0438\u0435 \u0441\u0442\u0440\u0430\u0442\u0435\u0433\u0438\u0438 \u043f\u0435\u0440\u0435\u0437\u0430\u043f\u0443\u0441\u043a\u0430 \u043f\u043e\u0434\u0447\u0438\u043d\u0435\u043d\u043d\u044b\u0445 \u044d\u043b\u0435\u043c\u0435\u043d\u0442\u043e\u0432 \u0432 \u0441\u043b\u0443\u0447\u0430\u0435 \u043e\u0448\u0438\u0431\u043a\u0438.  <\/p>\n<p>\u0414\u043b\u044f \u043e\u0442\u043f\u0440\u0430\u0432\u043a\u0438 \u0441\u043e\u043e\u0431\u0449\u0435\u043d\u0438\u0439 \u0438\u0437 \u0432\u043d\u0435\u0448\u043d\u0438\u0445 \u0438\u0441\u0442\u043e\u0447\u043d\u0438\u043a\u043e\u0432, \u043a\u043e\u0442\u043e\u0440\u044b\u0435 \u043d\u0435 \u043d\u0430\u0445\u043e\u0434\u044f\u0442\u0441\u044f \u0432 \u0441\u0438\u0441\u0442\u0435\u043c\u0435 \u0430\u043a\u0442\u043e\u0440\u043e\u0432 ActorSystem (\u0437\u0434\u0435\u0441\u044c \u044d\u0442\u043e <a href=\"https:\/\/github.com\/qquser\/Akka.Jobs\/blob\/master\/Akka.Jobs\/Services\/JobContext.cs\" rel=\"noopener noreferrer nofollow\">JobContext<\/a>) \u0438\u0441\u043f\u043e\u043b\u044c\u0437\u0443\u0435\u0442\u0441\u044f \u043a\u043e\u043c\u0430\u043d\u0434\u0430 \u043e\u0436\u0438\u0434\u0430\u043d\u0438\u044f \u043e\u0442\u0432\u0435\u0442\u0430 &#8212;  Ask.<\/p>\n<pre><code class=\"cs\">await _masterActor.Ask&lt;JobCreatedCommandResult>(command, currentTimeout);<\/code><\/pre>\n<p>Ask \u043e\u0436\u0438\u0434\u0430\u0435\u0442 \u043e\u0442\u0432\u0435\u0442\u0430 \u043e\u0442 \u043c\u043e\u0434\u0435\u043b\u0438 \u0430\u043a\u0442\u043e\u0440\u043e\u0432 <code>JobCreatedCommandResult<\/code>, \u0434\u043b\u044f \u0437\u0430\u0434\u0430\u043d\u043d\u043e\u0433\u043e \u043f\u0440\u043e\u043c\u0435\u0436\u0443\u0442\u043a\u0430 \u0432\u0440\u0435\u043c\u0435\u043d\u0438  currentTimeout. \u0413\u0434\u0435 \u043a\u043e\u043c\u0430\u043d\u0434\u0430 \u0438\u043c\u0435\u0435\u0442 \u0442\u0438\u043f <code>DoJobCommand<\/code> \u0438 \u043f\u0440\u0438\u043d\u0438\u043c\u0430\u0435\u0442\u0441\u044f  <a href=\"https:\/\/github.com\/qquser\/Akka.Jobs\/blob\/master\/Akka.Jobs\/Theater\/Master\/MasterActor.cs\" rel=\"noopener noreferrer nofollow\">MasterActor<\/a> \u043c\u0435\u0442\u043e\u0434\u043e\u043c  <code>Receive<\/code>, \u0437\u0430\u0434\u0430\u043d\u043d\u043e\u043c \u0432 \u043a\u043e\u043d\u0441\u0442\u0440\u0443\u043a\u0442\u043e\u0440\u0435.<\/p>\n<ul>\n<li>\n<p> <code>DoJobCommandHandler<\/code> &#8212; \u043c\u0435\u0442\u043e\u0434, \u043a\u043e\u0442\u043e\u0440\u044b\u0439 \u043f\u0435\u0440\u0435\u0434\u0430\u0441\u0442 \u0441\u043e\u043e\u0431\u0449\u0435\u043d\u0438\u0435 \u0441\u0443\u0449\u0435\u0441\u0442\u0432\u0443\u044e\u0449\u0435\u043c\u0443 \u0433\u0440\u0443\u043f\u043f\u043e\u0432\u043e\u043c\u0443 \u0430\u043a\u0442\u043e\u0440\u0443 \u0438\u043b\u0438 \u0441\u043e\u0437\u0434\u0430\u0441\u0442 \u0435\u0433\u043e \u043d\u043e\u0432\u044b\u0439 \u044d\u043a\u0437\u0435\u043c\u043f\u043b\u044f\u0440 \u0432 \u0441\u043b\u0443\u0447\u0430\u0435 \u043e\u0442\u0441\u0443\u0442\u0441\u0432\u0438\u044f \u0441 \u0441\u043e\u0437\u0440\u0430\u043d\u0435\u043d\u0438\u0435\u043c \u0441\u0441\u044b\u043b\u043a\u0438 IActorRef \u043d\u0430 \u043d\u0435\u0433\u043e.<\/p>\n<\/li>\n<\/ul>\n<ul>\n<li>\n<p><code>StopJobCommandHandler<\/code> &#8212; \u043c\u0435\u0442\u043e\u0434 \u0432\u044b\u0437\u044b\u0432\u0430\u0435\u043c\u044b\u0439 \u0432 \u043c\u043e\u043c\u0435\u043d\u0442 \u0437\u0430\u043f\u0440\u043e\u0441\u0430 \u043d\u0430 \u043e\u0441\u0442\u0430\u043d\u043e\u0432\u043a\u0443 \u0432\u043e\u0440\u043a\u0435\u0440\u0430.<\/p>\n<\/li>\n<li>\n<p><code>RequestAllWorkersInfoQueryHandler<\/code> &#8212; \u0445\u0435\u043d\u0434\u043b\u0435\u0440 \u0437\u0430\u043f\u0440\u043e\u0441\u043e\u0432 \u0441\u043e\u0441\u0442\u043e\u044f\u043d\u0438\u044f \u0433\u0440\u0443\u043f\u043f\u044b \u0430\u043a\u0442\u043e\u0440\u043e\u0432 \u043e\u043f\u0440\u0435\u0434\u0435\u043b\u0435\u043d\u043d\u043e\u0433\u043e \u0442\u0438\u043f\u0430 IJob <\/p>\n<\/li>\n<\/ul>\n<pre><code class=\"cs\">internal class MasterActor&lt;TIn, TOut> : ReceiveActor     where TIn : IJobInput     where TOut : IJobResult {      private readonly Dictionary&lt;string, IActorRef> _groupIdToActor = new();     private readonly Dictionary&lt;IActorRef, string> _actorToGroupId = new();      public MasterActor()     {         \/\/Commands         Receive&lt;DoJobCommand&lt;TIn>>(DoJobCommandHandler);         Receive&lt;StopJobCommand>(StopJobCommandHandler);          \/\/Queries         Receive&lt;RequestAllWorkersInfo>(RequestAllWorkersInfoQueryHandler);      }       private void DoJobCommandHandler(DoJobCommand&lt;TIn> doJobCommand)     {          if (_groupIdToActor.TryGetValue(doJobCommand.GroupName, out var actorRef))         {             actorRef.Forward(doJobCommand);             return;         }          var groupActorProps = DependencyResolver             .For(Context.System)             .Props&lt;GroupActor&lt;TIn,TOut>>();          var groupActor = Context             .ActorOf(groupActorProps, $\"group-{doJobCommand.GroupName}\");          Context.Watch(groupActor);          groupActor.Forward(doJobCommand);          _groupIdToActor.Add(doJobCommand.GroupName, groupActor);         _actorToGroupId.Add(groupActor, doJobCommand.GroupName);      }      private void StopJobCommandHandler(StopJobCommand command)     {         if (!_groupIdToActor.ContainsKey(command.GroupName))         {             Sender.Tell(new StopJobCommandResult(false, $\"Group Actor list does not contain {command.GroupName}\"));             return;         }          _groupIdToActor[command.GroupName].Forward(command);     } ...<\/code><\/pre>\n<h2>GroupActor <\/h2>\n<p>DoJobCommandHandler \u0434\u043e\u043b\u0436\u0435\u043d \u0441\u043e\u0437\u0434\u0430\u0442\u044c \u0434\u043e\u0447\u0435\u0440\u043d\u0438\u0439 \u0430\u043a\u0442\u043e\u0440 <a href=\"https:\/\/github.com\/qquser\/Akka.Jobs\/blob\/master\/Akka.Jobs\/Theater\/Master\/Groups\/GroupActor.cs\" rel=\"noopener noreferrer nofollow\">GroupActor<\/a>, \u043a\u043e\u0442\u043e\u0440\u044b\u0439 \u043e\u043f\u0438\u0448\u0435\u0442 \u0433\u0440\u0443\u043f\u043f\u0443 \u0432\u044b\u043f\u043e\u043b\u043d\u044f\u0435\u043c\u044b\u0445 \u0437\u0430\u0434\u0430\u0447. \u0415\u0433\u043e \u0444\u0443\u043d\u043a\u0446\u0438\u044f \u043f\u0440\u043e\u0441\u0442\u0430, \u043e\u043d \u0434\u043e\u043b\u0436\u0435\u043d \u043f\u0435\u0440\u0435\u0434\u0430\u0432\u0430\u0442\u044c \u0441\u043e\u043e\u0431\u0449\u0435\u043d\u0438\u044f \u0443\u043f\u0440\u0430\u0432\u043b\u0435\u043d\u0446\u0430\u043c \u0440\u0430\u0431\u043e\u0447\u0438\u0445 \u0438 \u0441\u043e\u0445\u0440\u0430\u043d\u044f\u0442\u044c \u0441\u0441\u044b\u043b\u043a\u0438 \u043d\u0430 \u0434\u043e\u0447\u0435\u0440\u043d\u0438\u0435 \u0430\u043a\u0442\u043e\u0440\u044b \u0434\u043b\u044f \u043f\u0440\u0435\u0434\u043e\u0441\u0442\u0430\u0432\u043b\u0435\u043d\u0438\u044f \u0432 \u0434\u0430\u043b\u044c\u043d\u0435\u0439\u0448\u0435\u043c \u0432\u043e\u0437\u043c\u043e\u0436\u043d\u043e\u0441\u0442\u0438 \u043e\u0431\u0440\u0430\u0442\u0438\u0442\u044c\u0441\u044f \u043a \u0438\u0445 \u0441\u043e\u0441\u0442\u043e\u044f\u043d\u0438\u044e. <\/p>\n<ul>\n<li>\n<p><code>TrySaveWorkerActorRefCommand<\/code> &#8212; \u0441\u043e\u043e\u0431\u0449\u0435\u043d\u0438\u0435 \u043a\u043e\u0442\u043e\u0440\u043e\u0435 \u043f\u0435\u0440\u0435\u0434\u0430\u0435\u0442\u0441\u044f \u043e\u0442 workerActor \u0434\u043b\u044f \u0441\u043e\u0445\u0440\u0430\u043d\u0435\u043d\u0438\u044f \u0441\u0441\u044b\u043b\u043a\u0438 IActorRef \u0432 \u0433\u0440\u0443\u043f\u043f\u043e\u0432\u043e\u043c \u0430\u043a\u0442\u043e\u0440\u0435.<\/p>\n<\/li>\n<li>\n<p><code>ManagerActorTerminatedHandler<\/code> &#8212; \u0432\u044b\u0437\u044b\u0432\u0430\u0435\u0442\u0441\u044f \u043f\u043e\u0441\u043b\u0435 \u043e\u0441\u0442\u0430\u043d\u043e\u0432\u043a\u0438 <code>ManagerActor<\/code> \u0438 \u0443\u0434\u0430\u043b\u044f\u0435\u0442 \u0441\u0441\u044b\u043b\u043a\u0438 \u043d\u0430 \u043e\u0431\u044a\u0435\u043a\u0442\u044b <code>IActorRef<\/code> \u0434\u043b\u044f <code>ManagerActor<\/code> \u0438 <code>WorkerActor<\/code>.<\/p>\n<\/li>\n<\/ul>\n<pre><code class=\"cs\">internal class GroupActor&lt;TIn, TOut> : ReceiveActor     where TIn : IJobInput     where TOut : IJobResult {      private string? _groupId;      private readonly Dictionary&lt;Guid, IActorRef> _idToManagerActor = new();     private readonly Dictionary&lt;IActorRef, Guid> _managerActorToId = new();      private readonly Dictionary&lt;IActorRef, Guid> _workerActorToId = new();     private readonly Dictionary&lt;Guid, IActorRef> _idToWorkerActor = new();        public GroupActor()     {         \/\/Commands         Receive&lt;DoJobCommand&lt;TIn>>(DoJobCommandHandler);         Receive&lt;StopJobCommand>(StopJobCommandHandler);          \/\/Queries         Receive&lt;RequestAllWorkersInfo>(RequestAllWorkersInfoQueryHandler);          \/\/Internal         Receive&lt;TrySaveWorkerActorRefCommand>(TrySaveWorkerActorRefCommandHandler);         Receive&lt;Terminated>(ManagerActorTerminatedHandler);      }      private void DoJobCommandHandler(DoJobCommand&lt;TIn> doJobCommand)     {         if (_groupId != null &amp;&amp; doJobCommand.GroupName != _groupId)         {             var message = \"Ignoring Create Worker Actor\";             Sender.Tell(doJobCommand.IsCreateCommand                     ? new JobCreatedCommandResult(false, message, doJobCommand.JobId)                     : new JobDoneCommandResult(false, message, doJobCommand.JobId));             return;         }          if (_idToManagerActor.ContainsKey(doJobCommand.JobId))         {             var message = $\"{doJobCommand.JobId} Actor Exists.\";             Sender.Tell(doJobCommand.IsCreateCommand                 ? new JobCreatedCommandResult(false, message, doJobCommand.JobId)                 : new JobDoneCommandResult(false, message, doJobCommand.JobId));             return;         }          _groupId ??= doJobCommand.GroupName;          var managerActorProps = DependencyResolver             .For(Context.System)             .Props&lt;ManagerActor&lt;TIn,TOut>>();                  var managerActor = Context.ActorOf(managerActorProps,             $\"manager-{doJobCommand.JobId}\");          Context.Watch(managerActor);          _idToManagerActor.Add(doJobCommand.JobId, managerActor);         _managerActorToId.Add(managerActor, doJobCommand.JobId);         managerActor.Forward(doJobCommand);     }      private void ManagerActorTerminatedHandler(Terminated t)     {         var workerId = _managerActorToId[t.ActorRef];         _managerActorToId.Remove(t.ActorRef);         _idToManagerActor.Remove(workerId);          if (!_idToWorkerActor.TryGetValue(workerId, out var workerActorRef))             return;         _workerActorToId.Remove(workerActorRef);         _idToWorkerActor.Remove(workerId);     } ...<\/code><\/pre>\n<h2>ManagerActor<\/h2>\n<p>\u0421 \u043f\u043e\u0432\u0435\u0434\u0435\u043d\u0438\u0435\u043c <a href=\"https:\/\/github.com\/qquser\/Akka.Jobs\/blob\/master\/Akka.Jobs\/Theater\/Master\/Groups\/Workers\/ManagerActor.cs\" rel=\"noopener noreferrer nofollow\">ManagerActor<\/a> \u0434\u0435\u043b\u0430 \u043e\u0431\u0441\u0442\u043e\u044f\u0442 \u0447\u0443\u0442\u044c \u0441\u043b\u043e\u0436\u043d\u0435\u0435, \u0435\u043c\u0443 \u043d\u0435\u043e\u0431\u0445\u043e\u0434\u0438\u043c\u043e \u043e\u043f\u0440\u0435\u0434\u0435\u043b\u0438\u0442\u044c \u0441\u0442\u0440\u0430\u0442\u0435\u0433\u0438\u044e \u043f\u043e\u0432\u0435\u0434\u0435\u043d\u0438\u044f \u043f\u0440\u0438 \u0432\u043e\u0437\u043d\u0438\u043a\u043d\u043e\u0432\u0435\u043d\u0438\u0438 \u043e\u0448\u0438\u0431\u043e\u043a \u0443 \u0440\u0430\u0431\u043e\u0447\u0435\u0433\u043e  <a href=\"https:\/\/github.com\/qquser\/Akka.Jobs\/blob\/master\/Akka.Jobs\/Theater\/Master\/Groups\/Workers\/WorkerActor.cs\" rel=\"noopener noreferrer nofollow\">WorkerActor<\/a>, \u0438 \u0441\u043e\u0445\u0440\u0430\u043d\u0438\u0442\u044c \u043d\u0430\u0447\u0430\u043b\u044c\u043d\u044b\u0439 \u0437\u0430\u043f\u0440\u043e\u0441 \u00ab<a href=\"https:\/\/github.com\/qquser\/Akka.Jobs\/blob\/master\/Akka.Jobs\/Theater\/Master\/Groups\/Workers\/Messages\/WorkerDoJobCommand.cs\" rel=\"noopener noreferrer nofollow\">WorkerDoJobCommand<\/a>\u00bb \u0434\u043b\u044f \u043f\u043e\u0432\u0442\u043e\u0440\u043d\u044b\u0445 \u043e\u0442\u043f\u0440\u0430\u0432\u043e\u043a \u044d\u0442\u043e\u0433\u043e \u0437\u0430\u043f\u0440\u043e\u0441\u0430 \u0432 \u043c\u043e\u043c\u0435\u043d\u0442\u044b \u043f\u0435\u0440\u0435\u0437\u0430\u043f\u0443\u0441\u043a\u0430. <\/p>\n<pre><code class=\"cs\">internal class ManagerActor&lt;TIn, TOut> : ReceiveActor     where TIn : IJobInput     where TOut : IJobResult  {     \/\/\u041f\u0430\u0440\u0430\u043c\u0435\u0442\u0440\u044b \u0441\u0442\u0440\u0430\u0442\u0435\u0433\u0438\u0438 \u043f\u0435\u0440\u0435\u0437\u0430\u043f\u0443\u0441\u043a\u0430     private int _currentNrOfRetries;     private int _maxNrOfRetries;     private TimeSpan _minBackoff;     private TimeSpan _maxBackoff;      \/\/\u0421\u0441\u044b\u043b\u043a\u0430 \u043d\u0430 \u043e\u0442\u043f\u0440\u0430\u0432\u0438\u0442\u0435\u043b\u044c \u043a\u043e\u043c\u0430\u043d\u0434\u044b \u043d\u0430 \u0432\u044b\u043f\u043e\u043b\u043d\u0435\u043d\u0438\u0435 \u0440\u0430\u0431\u043e\u0442\u044b     private IActorRef? _doJobCommandSender;     \/\/BackoffSupervisor     private IActorRef? _workerSupervisorActor;     \/\/\u041a\u043e\u043c\u0430\u043d\u0434\u0430 \u0434\u043b\u044f \u0434\u043e\u0447\u0435\u0440\u043d\u0435\u0433\u043e \u0430\u043a\u0442\u043e\u0440\u0430 \u0434\u043b\u044f \u043f\u043e\u0432\u0442\u043e\u0440\u043d\u043e\u0439 \u043e\u0442\u043f\u0440\u0430\u0432\u043a\u0438 \u0432 \u043c\u043e\u043c\u0435\u043d\u0442 \u0440\u0435\u0441\u0442\u0430\u0440\u0442\u043e\u0432     private WorkerDoJobCommand&lt;TIn>? _doJobCommand;      private Guid _jobId;     private bool _startedFlag;      \/\/StopJobCommandHandler \u043f\u0435\u0440\u0435\u0434\u0430\u043d\u043d\u044b\u0439 \u043e\u0442 JobContext \u0432\u044b\u0437\u043e\u0432\u0435\u0442 \u043e\u0442\u043c\u0435\u043d\u0443 \u0437\u0430\u0434\u0430\u0447\u0438     private readonly CancellationTokenSource _cancellationTokenSource = new ();      private readonly ILogger&lt;ManagerActor&lt;TIn, TOut>> _logger;      public ManagerActor(ILogger&lt;ManagerActor&lt;TIn, TOut>> logger)     {         _logger = logger;          \/\/Commands          Receive&lt;DoJobCommand&lt;TIn>>(DoJobCommandHandler);         Receive&lt;StopJobCommand>(StopJobCommandHandler);          \/\/Queries          Receive&lt;ReadWorkerInfoCommand>(ReadWorkerInfoCommandHandler);          \/\/Internal         Receive&lt;TrySaveWorkerActorRefCommand>(TrySaveWorkerActorRefCommandHandler);         Receive&lt;GiveMeWorkerDoJobCommand>(GiveMeWorkerDoJobCommandHandler);         Receive&lt;Terminated>(WorkerActorTerminatedHandler);      }   ...<\/code><\/pre>\n<ul>\n<li>\n<p><code>DoJobCommandHandler<\/code> &#8212; \u0442\u043e\u043b\u044c\u043a\u043e \u0441\u043e\u0437\u0434\u0430\u0435\u0442 \u0432\u043e\u0440\u043a\u0435\u0440\u0430 \u0431\u0435\u0437 \u043e\u0442\u043f\u0440\u0430\u0432\u043a\u0438 \u0441\u043e\u043e\u0431\u0449\u0435\u043d\u0438\u044f \u043d\u0430 \u0432\u044b\u043f\u043e\u043b\u043d\u0435\u043d\u0438\u0435 \u043a\u043e\u043c\u0430\u043d\u0434\u044b, \u0438 \u0437\u0430\u0434\u0430\u0435\u0442 \u0435\u043c\u0443 \u0441\u0442\u0440\u0430\u0442\u0435\u0433\u0438\u044e \u043f\u0435\u0440\u0435\u0437\u0430\u043f\u0443\u0441\u043a\u0430, \u043a\u043e\u0442\u043e\u0440\u0430\u044f \u043e\u043f\u0440\u0435\u0434\u0435\u043b\u0435\u043d\u0430 \u00ab<code>BackoffSupervisor<\/code>\u00bb \u0432 \u043c\u043e\u043c\u0435\u043d\u0442 \u0441\u043e\u0437\u0434\u0430\u043d\u0438\u044f <a href=\"https:\/\/github.com\/qquser\/Akka.Jobs\/blob\/master\/Akka.Jobs\/Theater\/Master\/Groups\/Workers\/WorkerActor.cs\" rel=\"noopener noreferrer nofollow\">WorkerActor<\/a>. \u041f\u0435\u0440\u0435\u0437\u0430\u043f\u0443\u0441\u043a \u0432\u043e\u0440\u043a\u0435\u0440\u0430 \u0431\u0443\u0434\u0435\u0442 \u043f\u0440\u043e\u0438\u0437\u0432\u0435\u0434\u0435\u043d \u0435\u0441\u043b\u0438 \u0432\u043e\u0437\u043d\u0438\u043a\u043d\u0435\u0442 \u043e\u0448\u0438\u0431\u043a\u0430 \u0432 \u0441\u0430\u043c\u043e\u043c \u0432\u043e\u0440\u043a\u0435\u0440\u0435 \u0438 \u0431\u0443\u0434\u0435\u0442 \u0432\u044b\u043f\u043e\u043b\u043d\u0435\u043d \u043a\u043e\u043b\u0438\u0447\u0435\u0441\u0442\u0432\u043e \u0440\u0430\u0432\u043d\u043e\u0435 <code>maxNrOfRetries<\/code> \u0440\u0430\u0437 \u0432 \u0438\u043d\u0442\u0435\u0440\u0432\u0430\u043b\u0435 \u043e\u0442  <code>minBackoff<\/code> \u0434\u043e  <code>maxBackoff<\/code>. \u0418\u043d\u0442\u0435\u0440\u0432\u0430\u043b \u043d\u0435\u043e\u0431\u0445\u043e\u0434\u0438\u043c \u0434\u043b\u044f \u0442\u043e\u0433\u043e, \u0447\u0442\u043e\u0431\u044b \u043f\u043e\u0432\u0442\u043e\u0440\u043d\u044b\u0435 \u043f\u043e\u043f\u044b\u0442\u043a\u0438 \u0432\u044b\u043f\u043e\u043b\u043d\u0438\u0442\u044c \u0440\u0430\u0431\u043e\u0442\u0443 \u0432 \u0441\u043b\u0443\u0447\u0430\u0435 \u043f\u043e\u0434\u043a\u043b\u044e\u0447\u0435\u043d\u0438\u044f \u043a \u0432\u043d\u0435\u0448\u043d\u0438\u043c \u0440\u0435\u0441\u0443\u0440\u0441\u0430\u043c \u0440\u0430\u0432\u043d\u043e\u043c\u0435\u0440\u043d\u043e \u0440\u0430\u0441\u043f\u0440\u0435\u0434\u0435\u043b\u0438\u043b\u0438 \u0437\u0430\u043f\u0440\u043e\u0441\u044b \u0432 \u0437\u0430\u0434\u0430\u043d\u043d\u044b\u0439 \u043f\u0440\u043e\u043c\u0435\u0436\u0443\u0442\u043e\u043a \u0432\u0440\u0435\u043c\u0435\u043d\u0438. <\/p>\n<\/li>\n<li>\n<p><code>GiveMeWorkerDoJobCommandHandler<\/code> &#8212; \u043e\u0431\u0440\u0430\u0431\u043e\u0442\u0447\u0438\u043a \u0441\u043e\u043e\u0431\u0449\u0435\u043d\u0438\u044f <code>GiveMeWorkerDoJobCommand<\/code>, \u043a\u043e\u0442\u043e\u0440\u043e\u0435 \u043f\u0440\u0438\u0441\u044b\u043b\u0430\u0435\u0442 \u0434\u043e\u0447\u0435\u0440\u043a\u0438\u0439 \u0432\u043e\u0440\u043a\u0435\u0440 \u0430\u043a\u0442\u043e\u0440 \u0432 \u043c\u043e\u043c\u0435\u043d\u0442 \u0438\u043d\u0438\u0446\u0438\u0430\u043b\u0438\u0437\u0430\u0446\u0438\u0438 \u0441\u0432\u043e\u0435\u0433\u043e \u0441\u043e\u0441\u0442\u043e\u044f\u043d\u0438\u044f &#8212; \u044d\u0442\u043e \u043d\u0435\u043e\u0431\u0445\u043e\u0434\u0438\u043c\u043e \u0434\u043b\u044f \u043f\u0435\u0440\u0435\u0437\u0430\u043f\u0443\u0441\u043a\u043e\u0432, \u0442\u0430\u043a \u043a\u0430\u043a \u0435\u0441\u043b\u0438 \u043e\u0442\u043f\u0440\u0430\u0432\u0438\u0442\u044c \u0441\u043e\u043e\u0431\u0449\u0435\u043d\u0438\u0435 \u0432 \u0441\u0430\u043c\u043e\u043c <code>DoJobCommandHandler<\/code>, \u043a\u043e\u0442\u043e\u0440\u044b\u0439 \u0432\u044b\u043f\u043e\u043b\u043d\u044f\u0435\u0442\u0441\u044f \u043e\u0434\u0438\u043d \u0440\u0430\u0437, \u0442\u043e \u0432 \u043c\u043e\u043c\u0435\u043d\u0442 \u043f\u0430\u0434\u0435\u043d\u0438\u044f \u0432\u043e\u0440\u043a\u0435\u0440 \u0430\u043a\u0442\u043e\u0440\u0430 \u0435\u0433\u043e \u0440\u0430\u0431\u043e\u0442\u0430 \u043d\u0435 \u0431\u0443\u0434\u0435\u0442 \u043d\u0430\u0447\u0430\u0442\u0430 \u0437\u0430\u043d\u043e\u0432\u043e.<\/p>\n<\/li>\n<\/ul>\n<pre><code class=\"cs\">    private void DoJobCommandHandler(DoJobCommand&lt;TIn> doJobCommand)     {         if (_workerSupervisorActor != null)         {             var message = \"Ignoring Create Worker Actor\";             Sender.Tell(doJobCommand.IsCreateCommand                 ? new JobCreatedCommandResult(false, message, doJobCommand.JobId)                 : new JobDoneCommandResult(false, message, doJobCommand.JobId));             return;         }           _jobId = doJobCommand.JobId;         _maxNrOfRetries = doJobCommand.MaxNrOfRetries;         _minBackoff = doJobCommand.MinBackoff;         _maxBackoff = doJobCommand.MaxBackoff;         _doJobCommandSender = Sender;          var workerActorProps = DependencyResolver             .For(Context.System)             .Props&lt;WorkerActor&lt;TIn,TOut>>();          var supervisorOfWorkerActorProps = BackoffSupervisor.Props(             Backoff.OnFailure(                     workerActorProps,                     childName: $\"worker-{doJobCommand.JobId}\",                     minBackoff: _minBackoff,                     maxBackoff: _maxBackoff,                     randomFactor: 0.2,                     maxNrOfRetries: _maxNrOfRetries)                 .WithSupervisorStrategy(new OneForOneStrategy(exception =>                 {                     if (exception is TaskCanceledException                           || exception.InnerException is TaskCanceledException                         || _currentNrOfRetries >= _maxNrOfRetries)                     {                         var text = $\"BackoffSupervisor: jobId: {_jobId}\" +                                    $\" {exception?.Message}\" +                                    $\" InnerException: {exception?.InnerException?.Message}\";                         _logger.LogError(text);                         _doJobCommandSender.Tell(new JobDoneCommandResult(false, text, _jobId));                         return Directive.Stop;                     }                                        _currentNrOfRetries += 1;                     return Directive.Restart;                 })));          _workerSupervisorActor = Context             .ActorOf(supervisorOfWorkerActorProps, $\"supervisor-of-worker-{doJobCommand.JobId}\");          Context.Watch(_workerSupervisorActor);                _doJobCommand = new WorkerDoJobCommand&lt;TIn>(             doJobCommand.JobInput,             _doJobCommandSender,               doJobCommand.JobId,             _cancellationTokenSource,             doJobCommand.IsCreateCommand);     } ...<\/code><\/pre>\n<h2>WorkerActor<\/h2>\n<p>\u0414\u0430\u043b\u0435\u0435 \u043a\u043e\u043c\u0430\u043d\u0434\u0430 \u0432\u044b\u043f\u043e\u043b\u043d\u0435\u043d\u0438\u044f \u043f\u043e\u043f\u0430\u0434\u0430\u0435\u0442 \u043a \u0440\u0430\u0431\u043e\u0447\u0435\u043c\u0443 <a href=\"https:\/\/github.com\/qquser\/Akka.Jobs\/blob\/master\/Akka.Jobs\/Theater\/Master\/Groups\/Workers\/WorkerActor.cs\" rel=\"noopener noreferrer nofollow\">WorkerActor<\/a>, \u043a\u043e\u0442\u043e\u0440\u044b\u0439 \u043e\u0442\u043f\u0440\u0430\u0432\u0438\u0442 \u0441\u043e\u043e\u0431\u0449\u0435\u043d\u0438\u044f \u043e \u0441\u043e\u0437\u0434\u0430\u043d\u0438\u0438 \u0440\u0430\u0431\u043e\u0442\u044b <code>JobCreatedCommandResult<\/code> \u0438\u043b\u0438 \u043e \u0435\u0451 \u0437\u0430\u0432\u0435\u0440\u0448\u0435\u043d\u0438\u0438 <code>JobDoneCommandResult<\/code> \u0432 \u0437\u0430\u0432\u0438\u0441\u0438\u043c\u043e\u0441\u0442\u0438 \u043e\u0442 \u0438\u0437\u043d\u0430\u0447\u0430\u043b\u044c\u043d\u043e \u0432\u044b\u0431\u0440\u0430\u043d\u043d\u043e\u0433\u043e \u043c\u0435\u0442\u043e\u0434\u0430 \u0432 <code>IJobContext<\/code> <code>CreateJobAsync<\/code> \u0438\u043b\u0438 <code>DoJobAsync<\/code> \u0441\u043e\u043e\u0442\u0432\u0435\u0442\u0441\u0442\u0432\u0435\u043d\u043d\u043e. <\/p>\n<p>\u041f\u043e \u0437\u0430\u0432\u0435\u0440\u0448\u0435\u043d\u0438\u0438 \u0440\u0430\u0431\u043e\u0442\u044b <a href=\"https:\/\/github.com\/qquser\/Akka.Jobs\/blob\/master\/Akka.Jobs\/Theater\/Master\/Groups\/Workers\/WorkerActor.cs\" rel=\"noopener noreferrer nofollow\">WorkerActor<\/a> \u043f\u043e\u043b\u043e\u0436\u0435\u0442 \u0441\u0435\u0431\u0435 \u0437\u0430 \u0449\u0435\u043a\u0443 \u0441\u043c\u0435\u0440\u0442\u0435\u043b\u044c\u043d\u0443\u044e \u043f\u0438\u043b\u044e\u043b\u044e  <code>_self.Tell(PoisonPill.Instance)<\/code>, \u0447\u0442\u043e \u043f\u0440\u0438\u0432\u0435\u0434\u0435\u0442 \u043a \u0435\u0433\u043e \u043e\u0441\u0442\u0430\u043d\u043e\u0432\u043a\u0435 \u0438 \u043e\u0447\u0438\u0441\u0442\u043a\u0435 \u0440\u0435\u0441\u0443\u0440\u0441\u043e\u0432.  <\/p>\n<pre><code class=\"cs\">internal class WorkerActor&lt;TIn, TOut> : ReceiveActor     where TIn : IJobInput     where TOut : IJobResult {     private Guid _jobId;      private readonly IServiceScope _scope;     private readonly IActorRef _self;     private IJob&lt;TIn, TOut> _job;        public WorkerActor(IServiceProvider serviceProvider)     {         _self = Self;         _scope = serviceProvider.CreateScope();          \/\/Commands         Receive&lt;WorkerDoJobCommand&lt;TIn>>((msg) =>         {             WorkerDoJobCommandHandlerAsync(msg).PipeTo(_self);         });          \/\/Queries         Receive&lt;ReadWorkerInfoCommand>(ReadWorkerInfoCommandHandler);          \/\/Internal         Receive&lt;Status.Failure>(Failed);         Context.Parent.Tell(new GiveMeWorkerDoJobCommand());      }      private async Task WorkerDoJobCommandHandlerAsync(WorkerDoJobCommand&lt;TIn> command)     {         _jobId = command.JobId;          Context.Parent.Tell(new TrySaveWorkerActorRefCommand(_self, _jobId, command.DoJobCommandSender));          if(command.IsCreateCommand)             command.DoJobCommandSender.Tell(new JobCreatedCommandResult(true, \"\", _jobId));          var token = command.CancellationTokenSource.Token;         var jobResult = await _job.DoAsync(command.JobInput, token);          if(token.IsCancellationRequested)         {             if(!command.IsCreateCommand)                 command.DoJobCommandSender.Tell(new JobDoneCommandResult(false,                       \"Job was cancelled.\",                       command.JobId));             return;         }          if(!command.IsCreateCommand)             command.DoJobCommandSender.Tell(new JobDoneCommandResult(jobResult, \"Ok\", command.JobId));          _self.Tell(PoisonPill.Instance);     }<\/code><\/pre>\n<h2>\u0412\u043e\u0437\u043c\u043e\u0436\u043d\u043e\u0441\u0442\u044c \u043e\u0442\u043c\u0435\u043d\u044b \u0437\u0430\u0434\u0430\u0447<\/h2>\n<p>\u041f\u0440\u0435\u0434\u0443\u0441\u043c\u043e\u0442\u0440\u0435\u043d\u0430 \u0432\u043e\u0437\u043c\u043e\u0436\u043d\u043e\u0441\u0442\u044c \u043e\u0442\u043c\u0435\u043d\u044b \u0437\u0430\u0434\u0430\u0447\u0438. <a href=\"https:\/\/github.com\/qquser\/Akka.Jobs\/blob\/master\/Akka.Jobs\/Theater\/Master\/Groups\/Workers\/ManagerActor.cs\" rel=\"noopener noreferrer nofollow\">ManagerActor<\/a> \u0432 \u043c\u043e\u043c\u0435\u043d\u0442 \u043f\u043e\u043b\u0443\u0447\u0435\u043d\u0438\u044f \u043a\u043e\u043c\u0430\u043d\u0434\u044b <a href=\"https:\/\/github.com\/qquser\/Akka.Jobs\/blob\/master\/Akka.Jobs\/Theater\/Master\/Groups\/Workers\/Messages\/StopJobCommand.cs\" rel=\"noopener noreferrer nofollow\">StopJobCommand<\/a> \u043d\u0430 \u043e\u0441\u0442\u0430\u043d\u043e\u0432\u043a\u0443, \u0432\u044b\u0437\u044b\u0432\u0430\u0435\u0442 \u043e\u0442\u043c\u0435\u043d\u0443 \u0441\u0432\u043e\u0435\u0433\u043e  <code>_cancellationTokenSource.Cancel(),<\/code>  \u043a\u0430\u043d\u0441\u0435\u043b \u0442\u043e\u043a\u0435\u043d \u043a\u043e\u0442\u043e\u0440\u043e\u0433\u043e \u0431\u044b\u043b \u043f\u0440\u043e\u043a\u0438\u043d\u0443\u0442 \u0432 \u0434\u043e\u0447\u0435\u0440\u043d\u0438\u0439 <a href=\"https:\/\/github.com\/qquser\/Akka.Jobs\/blob\/master\/Akka.Jobs\/Theater\/Master\/Groups\/Workers\/WorkerActor.cs\" rel=\"noopener noreferrer nofollow\">WorkerActor<\/a>,  \u0438 \u043e\u0442\u043f\u0440\u0430\u0432\u043a\u0443 \u0435\u043c\u0443 \u0441\u043c\u0435\u0440\u0442\u0435\u043b\u044c\u043d\u043e\u0439 \u043f\u0438\u043b\u044e\u043b\u0438 <code>_workerSupervisorActor.Tell(PoisonPill.Instance).<\/code><\/p>\n<pre><code class=\"cs\">   private void StopJobCommandHandler(StopJobCommand _)     {         if (!_cancellationTokenSource.IsCancellationRequested)         {             _cancellationTokenSource.Cancel();             _workerSupervisorActor.Tell(PoisonPill.Instance);             Sender.Tell(new StopJobCommandResult(true, \"Ok\"));             return;         }         Sender.Tell(new StopJobCommandResult(false, \"Cancellation Requested Already.\"));     }<\/code><\/pre>\n<h2>DI &#8212; Microsoft.Extensions.DependencyInjection<\/h2>\n<p>\u0412  <a href=\"https:\/\/github.com\/qquser\/Akka.Jobs\/blob\/master\/Akka.Jobs\/Theater\/Master\/Groups\/Workers\/WorkerActor.cs\" rel=\"noopener noreferrer nofollow\">WorkerActor<\/a> \u0438\u043d\u044a\u0435\u043a\u0442\u0438\u0440\u043e\u0432\u0430\u043d \u0438\u043d\u0442\u0435\u0440\u0444\u0435\u0439\u0441 <code>IServiceProvider serviceProvider<\/code>, \u0447\u0442\u043e \u043f\u043e\u0437\u0432\u043e\u043b\u044f\u0435\u0442 \u0443\u043f\u0440\u0430\u0432\u043b\u044f\u0442\u044c \u0432\u0440\u0435\u043c\u0435\u043d\u0435\u043c \u0436\u0438\u0437\u043d\u0438 \u0441\u043a\u043e\u0443\u043f\u0430 <code>_scope<\/code> \u043e\u0442 \u043c\u043e\u043c\u0435\u043d\u0442\u0430 \u0438\u043d\u0438\u0446\u0438\u0430\u043b\u0438\u0437\u0430\u0446\u0438\u0438 \u0432\u043e\u0440\u043a\u0435\u0440\u0430 \u0434\u043e \u043c\u043e\u043c\u0435\u043d\u0442\u0430 \u043e\u0441\u0442\u0430\u043d\u043e\u0432\u043a\u0438 \u0430\u043a\u0442\u043e\u0440\u0430 \u0438 \u043e\u0447\u0438\u0441\u0442\u043a\u0438 \u0440\u0435\u0441\u0443\u0440\u0441\u043e\u0432. \u0414\u043b\u044f \u0434\u0436\u043e\u0431\u0430 \u043f\u043e\u043b\u044c\u0437\u043e\u0432\u0430\u0442\u0435\u043b\u044f \u0441\u043a\u043e\u0443\u043f &#8212; \u044d\u0442\u043e \u0432\u0441\u0435, \u0447\u0442\u043e \u043d\u0430\u0445\u043e\u0434\u0438\u0442\u0441\u044f \u0432\u043d\u0443\u0442\u0440\u0438 \u043c\u0435\u0442\u043e\u0434\u0430 <code>IJob.DoAsync<\/code>. \u0412\u044b\u0437\u043e\u0432 <code>_scope.Dispose(<\/code>) \u0442\u0430\u043a\u0436\u0435 \u0432\u044b\u0437\u043e\u0432\u0435\u0442 \u043c\u0435\u0442\u043e\u0434\u044b <code>Dispose<\/code>, \u0435\u0441\u043b\u0438 \u0432 \u0438\u043c\u043f\u043b\u0435\u043c\u0435\u043d\u0442\u0430\u0446\u0438\u0438 <code>IJob<\/code> \u0431\u0443\u0434\u0435\u0442 \u0442\u0430\u043a\u0436\u0435 \u0443\u043d\u0430\u0441\u043b\u0435\u0434\u043e\u0432\u0430\u043d <code>IDispoosable<\/code> \u0438\u043d\u0442\u0435\u0440\u0444\u0435\u0439\u0441.<\/p>\n<pre><code class=\"cs\">    protected override void PreStart()     {         _job = _scope.ServiceProvider.GetService&lt;IJob&lt;TIn, TOut>>();     }     protected override void PostStop()     {         _scope.Dispose();     }<\/code><\/pre>\n<h3>\u0417\u0430\u043f\u0440\u043e\u0441\u044b <\/h3>\n<p><a href=\"https:\/\/github.com\/qquser\/Akka.Jobs\/blob\/master\/Akka.Jobs\/Services\/JobContext.cs\" rel=\"noopener noreferrer nofollow\">JobContext<\/a> \u043f\u043e\u0437\u0432\u043e\u043b\u044f\u0435\u0442 \u0437\u0430\u043f\u0440\u043e\u0441\u0438\u0442\u044c \u0441\u043e\u0441\u0442\u043e\u044f\u043d\u0438\u0435 \u0430\u043a\u0442\u043e\u0440\u043e\u0432, \u043a\u043e\u0442\u043e\u0440\u044b\u0435 \u0431\u044b\u043b\u0438 \u0441\u043e\u0437\u0434\u0430\u043d\u044b \u0434\u043b\u044f \u043e\u043f\u0440\u0435\u0434\u0435\u043b\u0435\u043d\u043d\u043e\u0433\u043e \u0442\u0438\u043f\u0430 <code>IJob<\/code>.<\/p>\n<pre><code class=\"cs\">     public async Task&lt;IDictionary&lt;Guid, ReplyWorkerInfo&lt;TOut>>> GetAllJobsCurrentStatesAsync(long requestId,         TimeSpan? timeout = null)     {         var currentTimeout = timeout ?? _defaultTimeout;         var query = new RequestAllWorkersInfo(requestId, GetGroupName(), currentTimeout);         RespondAllWorkersInfo&lt;TOut> info = await _masterActor             .Ask&lt;RespondAllWorkersInfo&lt;TOut>>(query, currentTimeout);         return info.WorkersData;     } <\/code><\/pre>\n<h2>\u0418\u0441\u043f\u043e\u043b\u044c\u0437\u043e\u0432\u0430\u043d\u0438\u0435<\/h2>\n<p>\u0414\u043b\u044f \u0440\u0435\u0433\u0438\u0441\u0442\u0440\u0430\u0446\u0438\u0438 \u043d\u0435\u043e\u0431\u0445\u043e\u0434\u0438\u043c\u043e \u043f\u0440\u0438 \u0441\u0442\u0430\u0440\u0442\u0435 \u043f\u0440\u043e\u0435\u043a\u0442\u0430 \u0432\u044b\u0437\u0432\u0430\u0442\u044c \u043c\u0435\u0442\u043e\u0434\u044b<\/p>\n<pre><code class=\"cs\">\/\/Job library registration builder.Services.AddScoped&lt;IJob&lt;ForEachJobInput, ForEachJobResult>, ForEachJob>(); builder.Services.AddJobContext();<\/code><\/pre>\n<p>\u0413\u0434\u0435  <code>ForEachJob<\/code> \u2014 \u044d\u0442\u043e \u043f\u0440\u043e\u0441\u0442\u0430\u044f \u0442\u0435\u0441\u0442\u043e\u0432\u0430\u044f \u0437\u0430\u0434\u0430\u0447\u0430, \u043a\u043e\u0442\u043e\u0440\u0430\u044f \u043f\u0435\u0440\u0435\u0431\u0438\u0440\u0430\u0435\u0442 \u0437\u043d\u0430\u0447\u0435\u043d\u0438\u044f \u043e\u0442 0 \u0434\u043e <code>Count<\/code> c \u043e\u0436\u0438\u0434\u0430\u0435\u043d\u0438\u043c \u0441\u0435\u043a\u0443\u043d\u0434\u044b \u043c\u0435\u0436\u0434\u0443 \u0448\u0430\u0433\u0430\u043c\u0438. \u0412 \u0434\u0430\u043d\u043d\u043e\u043c \u0442\u0435\u0441\u0442\u043e\u0432\u043e\u043c \u0434\u0436\u043e\u0431\u0435 <code>ForEachJob<\/code> \u043e\u0442\u0434\u0435\u043b\u044c\u043d\u043e \u0443\u043d\u0430\u0441\u043b\u0435\u0434\u043e\u0432\u0430\u043d \u0438\u043d\u0442\u0435\u0440\u0444\u0435\u0439\u0441 <code>IDisposable<\/code>, \u0447\u0442\u043e \u043f\u043e\u0437\u0432\u043e\u043b\u044f\u0435\u0442 \u0434\u043e\u043f\u043e\u043b\u043d\u0438\u0442\u0435\u043b\u044c\u043d\u043e \u043e\u043f\u0440\u0435\u0434\u0435\u043b\u0438\u0442\u044c \u043c\u0435\u0445\u0430\u043d\u0438\u0437\u043c \u043e\u0447\u0438\u0441\u0442\u043a\u0438 \u0440\u0435\u0441\u0443\u0440\u0441\u043e\u0432 \u0432 \u043c\u043e\u043c\u0435\u043d\u0442 \u043e\u0441\u0442\u0430\u043d\u043e\u0432\u043a\u0438 \u0437\u0430\u0434\u0430\u0447\u0438 \u0438\u043b\u0438 \u043f\u043e\u0441\u043b\u0435 \u0435\u0451 \u0448\u0442\u0430\u0442\u043d\u043e\u0433\u043e \u0437\u0430\u0432\u0435\u0440\u0448\u0435\u043d\u0438\u044f \u0440\u0430\u0431\u043e\u0442\u044b. <\/p>\n<pre><code class=\"cs\">public class ForEachJob : IJob&lt;ForEachJobInput, ForEachJobResult>, IDisposable {     private int _currentState;      private readonly ILogger&lt;ForEachJob> _logger;     \/\/\u0417\u0434\u0435\u0441\u044c \u0432\u043e\u0437\u043c\u043e\u0436\u043d\u0430 \u0438\u043d\u044a\u0435\u043a\u0446\u0438\u044f \u043b\u044e\u0431\u043e\u0433\u043e \u0437\u0430\u0440\u0435\u0433\u0435\u0441\u0442\u0440\u0438\u0440\u043e\u0432\u0430\u043d\u043d\u043e\u0433\u043e \u0432 \u043f\u0440\u0438\u043b\u043e\u0436\u0435\u043d\u0438\u0438 \u0438\u043d\u0442\u0435\u0440\u0444\u0435\u0439\u0441\u0430      public ForEachJob(ILogger&lt;ForEachJob> logger)     {         _logger = logger;     }      public async Task&lt;bool> DoAsync(ForEachJobInput input, CancellationToken token)     {         foreach (var item in Enumerable.Range(0, input.Count))         {             if (token.IsCancellationRequested)                 return false;              _currentState = item;             _logger.LogInformation(item.ToString());             await Task.Delay(1000, token);         }          return true;     }      public ForEachJobResult GetCurrentState(Guid jobId)     {         return new ForEachJobResult         {             Id = jobId,             Data = _currentState         };     }      public void Dispose()     {         _logger.LogInformation(\"Dispose.\");     }  }<\/code><\/pre>\n<p>\u0412\u044b\u0437\u043e\u0432, \u043d\u0430\u043f\u0440\u0438\u043c\u0435\u0440, \u0438\u0437 \u043a\u043e\u043d\u0442\u0440\u043e\u043b\u043b\u0435\u0440\u0430 \u0431\u0443\u0434\u0435\u0442 \u0432\u044b\u0433\u043b\u044f\u0434\u0438\u0442\u044c \u0442\u0430\u043a:<\/p>\n<pre><code class=\"cs\">public class ForEachJobController : ControllerBase {     private readonly IJobContext&lt;ForEachJobInput, ForEachJobResult> _jobContext;          public ForEachJobController(       IJobContext&lt;ForEachJobInput, ForEachJobResult> jobContext)     {         _jobContext = jobContext;     }          [HttpPost]     [Route(nameof(CreateJob))]     public async Task&lt;JobCreatedCommandResult> CreateJob([FromBody] ForEachJobInput input)     {         return await _jobContext.CreateJobAsync(input);     }          [HttpPost]     [Route(nameof(DoJob))]     public async Task&lt;JobDoneCommandResult> DoJob([FromBody] ForEachJobInput input)     {         return await _jobContext.DoJobAsync(input);     }          [HttpPost]     [Route(nameof(StopJob))]     public async Task&lt;StopJobCommandResult> StopJob([FromBody] Guid jobId)     {         return await _jobContext.StopJobAsync(jobId);     }          [HttpGet]     [Route(nameof(GetAllJobs))]     public async Task&lt;ICollection&lt;ForEachJobResult?>> GetAllJobs(       [FromQuery] int requestId)     {         var result = await _jobContext             .GetAllJobsCurrentStatesAsync(requestId);         return result.Values.Select(x => x.Result).ToList();     } }<\/code><\/pre>\n<h2>\u0418\u0442\u043e\u0433<\/h2>\n<p><a href=\"https:\/\/getakka.net\" rel=\"noopener noreferrer nofollow\">Akka <\/a>\u043e\u0434\u0438\u043d \u0438\u0437 \u0432\u043e\u0437\u043c\u043e\u0436\u043d\u044b\u0445 \u0441\u043f\u043e\u0441\u043e\u0431\u043e\u0432 \u0437\u0430\u043f\u0443\u0441\u043a\u0430 \u043e\u0442\u043b\u043e\u0436\u0435\u043d\u043d\u044b\u0445 \u0437\u0430\u0434\u0430\u0447 \u0441 \u043f\u043e\u0442\u0435\u043d\u0446\u0438\u0430\u043b\u044c\u043d\u043e\u0439 \u0432\u043e\u0437\u043c\u043e\u0436\u043d\u043e\u0441\u0442\u044c\u044e \u043a\u043b\u0430\u0441\u0442\u0435\u0440\u0438\u0437\u0430\u0446\u0438\u0438 \u0440\u0435\u0448\u0435\u043d\u0438\u044f.<\/p>\n<\/p>\n<\/div>\n<\/div>\n<\/div>\n<p> <!----> <!----><\/div>\n<p> <!----> <!----><br \/> \u0441\u0441\u044b\u043b\u043a\u0430 \u043d\u0430 \u043e\u0440\u0438\u0433\u0438\u043d\u0430\u043b \u0441\u0442\u0430\u0442\u044c\u0438 <a href=\"https:\/\/habr.com\/ru\/articles\/741044\/\"> https:\/\/habr.com\/ru\/articles\/741044\/<\/a><\/p>\n","protected":false},"excerpt":{"rendered":"<div><\/div>\n<div id=\"post-content-body\">\n<div>\n<div class=\"article-formatted-body article-formatted-body article-formatted-body_version-2\">\n<div xmlns=\"http:\/\/www.w3.org\/1999\/xhtml\">\n<p>\u0414\u043e\u043f\u0443\u0441\u0442\u0438\u043c, \u043d\u0435\u043e\u0431\u0445\u043e\u0434\u0438\u043c\u043e \u0437\u0430\u043f\u0443\u0441\u0442\u0438\u0442\u044c \u043c\u043d\u043e\u0436\u0435\u0441\u0442\u0432\u043e \u0444\u043e\u043d\u043e\u0432\u044b\u0445 \u0437\u0430\u0434\u0430\u0447 \u0432 .Net \u0441 \u0432\u043e\u0437\u043c\u043e\u0436\u043d\u043e\u0441\u0442\u044c\u044e \u0432 \u0434\u0430\u043b\u044c\u043d\u0435\u0439\u0448\u0435\u043c \u043e\u0431\u0440\u0430\u0442\u0438\u0442\u044c\u0441\u044f \u043a \u0438\u0445 \u0441\u043e\u0441\u0442\u043e\u044f\u043d\u0438\u044e. \u041e\u0431\u0440\u0430\u0449\u0435\u043d\u0438\u0435 \u043a \u0447\u043b\u0435\u043d\u0430\u043c \u043a\u043b\u0430\u0441\u0441\u0430 \u0437\u0430\u043f\u0443\u0449\u0435\u043d\u043d\u043e\u0439 \u0437\u0430\u0434\u0430\u0447\u0438 \u043c\u043e\u0436\u0435\u0442 \u0431\u044b\u0442\u044c \u043f\u043e\u043b\u0435\u0437\u043d\u043e, \u0435\u0441\u043b\u0438 \u043d\u0435\u043e\u0431\u0445\u043e\u0434\u0438\u043c\u043e \u043e\u0434\u043d\u043e\u0437\u043d\u0430\u0447\u043d\u043e \u043e\u043f\u0440\u0435\u0434\u0435\u043b\u0438\u0442\u044c \u0442\u0435\u043a\u0443\u0449\u0435\u0435 \u0441\u043e\u0441\u0442\u043e\u044f\u043d\u0438\u0435 \u043e\u0431\u044a\u0435\u043a\u0442\u0430 \u0432 \u043c\u043e\u043c\u0435\u043d\u0442 \u0432\u044b\u043f\u043e\u043b\u043d\u0435\u043d\u0438\u044f.  <\/p>\n<h2>\u041e\u0434\u043d\u043e \u0438\u0437 \u0447\u0430\u0441\u0442\u043d\u044b\u0445 \u0440\u0435\u0448\u0435\u043d\u0438\u0439 \u2014 \u043c\u043e\u0434\u0435\u043b\u044c \u0430\u043a\u0442\u043e\u0440\u043e\u0432<\/h2>\n<p>\u041c\u043e\u0434\u0435\u043b\u044c \u0430\u043a\u0442\u043e\u0440\u043e\u0432 \u043f\u043e\u0437\u0432\u043e\u043b\u044f\u0435\u0442 \u0437\u0430\u043f\u0443\u0441\u043a\u0430\u0442\u044c  \u0444\u043e\u043d\u043e\u0432\u044b\u0435 \u0437\u0430\u0434\u0430\u0447\u0438 \u0438 \u043e\u0431\u0440\u0430\u0449\u0430\u0442\u044c\u0441\u044f \u043a \u0438\u0445 \u0442\u0435\u043a\u0443\u0449\u0435\u043c\u0443 \u0441\u043e\u0441\u0442\u043e\u044f\u043d\u0438\u044e.  <\/p>\n<h2>\u0418\u043d\u0442\u0435\u0440\u0444\u0435\u0439\u0441\u044b<\/h2>\n<p>\u041e\u043f\u0440\u0435\u0434\u0435\u043b\u0438\u043c \u0438\u043d\u0442\u0435\u0440\u0444\u0435\u0439\u0441, \u043a\u043e\u0442\u043e\u0440\u044b\u0439 \u043e\u043f\u0438\u0448\u0435\u0442 \u0432\u044b\u043f\u043e\u043b\u043d\u044f\u0435\u043c\u0443\u044e \u0440\u0430\u0431\u043e\u0442\u0443 \u2014 <a href=\"https:\/\/github.com\/qquser\/Akka.Jobs\/blob\/master\/Akka.Jobs\/Interfaces\/IJob.cs\" rel=\"noopener noreferrer nofollow\">IJob<\/a>, \u0441 \u043e\u0431\u044f\u0437\u0430\u0442\u0435\u043b\u044c\u043d\u043e\u0439 \u043f\u0435\u0440\u0435\u0434\u0430\u0447\u0435\u0439 \u0432 \u043c\u0435\u0442\u043e\u0434  <code>DoAsync<\/code> &#8212; <code>CancellationToken token<\/code>.<\/p>\n<pre><code class=\"cs\">public interface IJob&lt;in TIn, out TOut>     where TIn : IJobInput     where TOut : IJobResult   {     Task&lt;bool> DoAsync(TIn input, CancellationToken token);      \/\/\/ &lt;summary>     \/\/\/ Describes the state of the fields of the IJob class that are changed by the DoAsync method.     \/\/\/ &lt;\/summary>     TOut GetCurrentState(Guid jobId); }<\/code><\/pre>\n<p>\u0418\u043d\u0442\u0435\u0440\u0444\u0435\u0439\u0441 \u0434\u0436\u043e\u0431\u0430 &#8212; <a href=\"https:\/\/github.com\/qquser\/Akka.Jobs\/blob\/master\/Akka.Jobs\/Interfaces\/IJob.cs\" rel=\"noopener noreferrer nofollow\">IJob<\/a> \u043e\u043f\u0440\u0435\u0434\u0435\u043b\u0435\u043d, \u043d\u043e \u0432\u044b\u0437\u043e\u0432 \u0435\u0433\u043e \u0438\u043c\u043f\u043b\u0435\u043c\u0435\u043d\u0442\u0430\u0446\u0438\u0438 \u043d\u0430\u043f\u0440\u044f\u043c\u0443\u044e \u043d\u0435 \u0434\u0430\u0441\u0442 \u0438\u0441\u043a\u043e\u043c\u044b\u0445 \u0440\u0435\u0437\u0443\u043b\u044c\u0442\u0430\u0442\u043e\u0432, \u043f\u043e\u044d\u0442\u043e\u043c\u0443 \u043d\u0435\u043e\u0431\u0445\u043e\u0434\u0438\u043c\u043e \u043e\u043f\u0440\u0435\u0434\u0435\u043b\u0438\u0442\u044c \u043a\u043e\u043d\u0442\u0435\u043a\u0441\u0442 \u0432\u044b\u043f\u043e\u043b\u043d\u0435\u043d\u0438\u044f \u0434\u0436\u043e\u0431\u043e\u0432  <a href=\"https:\/\/github.com\/qquser\/Akka.Jobs\/blob\/master\/Akka.Jobs\/Interfaces\/IJobContext.cs\" rel=\"noopener noreferrer nofollow\">IJobContext<\/a>, \u043a\u043e\u0442\u043e\u0440\u044b\u0439 \u043e\u0431\u044a\u0435\u0434\u0438\u043d\u0438\u0442 \u0433\u0440\u0443\u043f\u043f\u0443 \u0432\u044b\u043f\u043e\u043b\u043d\u044f\u0435\u043c\u044b\u0445 \u043e\u0434\u043d\u043e\u0442\u0438\u043f\u043d\u044b\u0445 \u0437\u0430\u0434\u0430\u0447. \u0417\u0434\u0435\u0441\u044c \u043d\u0435\u043e\u0431\u0445\u043e\u0434\u0438\u043c\u043e \u043f\u0440\u0435\u0434\u043e\u0441\u0442\u0430\u0432\u0438\u0442\u044c \u0432\u043e\u0437\u043c\u043e\u0436\u043d\u043e\u0441\u0442\u044c \u043d\u0435 \u0442\u043e\u043b\u044c\u043a\u043e \u0437\u0430\u043f\u0443\u0441\u043a\u0430\u0442\u044c \u0444\u043e\u043d\u043e\u0432\u044b\u0435 \u0442\u0430\u0441\u043a\u0438 <code>CreateJobAsync<\/code>, \u043d\u043e \u0438 \u043e\u0436\u0438\u0434\u0430\u0442\u044c \u043f\u043e\u043b\u043d\u043e\u0433\u043e \u0432\u044b\u043f\u043e\u043b\u043d\u0435\u043d\u0438\u044f \u0437\u0430\u0434\u0430\u0447\u0438 <code>DoJobAsync<\/code>.  <\/p>\n<pre><code class=\"cs\">public interface IJobContext&lt;in TIn, TOut>     where TIn : IJobInput     where TOut : IJobResult {      \/\/\/ &lt;summary>     \/\/\/ Create a background job     \/\/\/ &lt;\/summary>     \/\/\/ &lt;returns>Job Id&lt;\/returns>     Task&lt;JobCreatedCommandResult> CreateJobAsync(TIn input,         int? maxNrOfRetries = null,         TimeSpan? minBackoff = null,         TimeSpan? maxBackoff = null,           Guid? jobId = null,         TimeSpan? timeout = null);      \/\/\/ &lt;summary>     \/\/\/ Waiting for a response about the completion of the job     \/\/\/ &lt;\/summary>     Task&lt;JobDoneCommandResult> DoJobAsync(TIn input,         int? maxNrOfRetries = null, TimeSpan? minBackoff = null, TimeSpan? maxBackoff = null,  Guid? jobId = null, TimeSpan? timeout = null);      Task&lt;StopJobCommandResult> StopJobAsync(Guid jobId, TimeSpan? timeout = null);      Task&lt;IDictionary&lt;Guid, ReplyWorkerInfo&lt;TOut>>> GetAllJobsCurrentStatesAsync(long requestId, TimeSpan? timeout = null); }<\/code><\/pre>\n<h2>\u0420\u0435\u0430\u043b\u0438\u0437\u0430\u0446\u0438\u044f<\/h2>\n<p>\u041e\u0441\u043d\u043e\u0432\u043d\u043e\u0439 \u0438\u0434\u0435\u0435\u0439 \u043c\u043e\u0434\u0435\u043b\u0438 \u0430\u043a\u0442\u043e\u0440\u043e\u0432 \u044f\u0432\u043b\u044f\u0435\u0442\u0441\u044f \u0438\u0437\u043e\u043b\u044f\u0446\u0438\u044f \u0441\u043e\u0441\u0442\u043e\u044f\u043d\u0438\u044f \u043a\u0430\u0436\u0434\u043e\u0433\u043e \u043e\u0431\u044a\u0435\u043a\u0442\u0430 \u043c\u043e\u0434\u0435\u043b\u0438 \u043e\u0442 \u0432\u043d\u0435\u0448\u043d\u0435\u0433\u043e \u0432\u043c\u0435\u0448\u0430\u0442\u0435\u043b\u044c\u0441\u0442\u0432\u0430, \u0447\u0442\u043e \u0434\u043e\u043b\u0436\u043d\u043e \u0433\u0430\u0440\u0430\u043d\u0442\u0438\u0440\u043e\u0432\u0430\u0442\u044c \u043f\u0440\u0435\u0434\u0441\u043a\u0430\u0437\u0443\u0435\u043c\u043e\u0435 \u0438\u0437\u043c\u0435\u043d\u0435\u043d\u0438\u0435 \u0441\u0432\u043e\u0435\u0433\u043e \u0441\u043e\u0441\u0442\u043e\u044f\u043d\u0438\u044f. \u041e\u0431\u0449\u0435\u043d\u0438\u0435 \u043c\u0435\u0436\u0434\u0443 \u0430\u043a\u0442\u043e\u0440\u0430\u043c\u0438 \u043f\u0440\u043e\u0438\u0441\u0445\u043e\u0434\u0438\u0442 \u0447\u0435\u0440\u0435\u0437 \u043e\u0447\u0435\u0440\u0435\u0434\u0438 \u0441\u043e\u043e\u0431\u0449\u0435\u043d\u0438\u0439, \u0432 \u043a\u043e\u0442\u043e\u0440\u044b\u0435 \u0434\u043b\u044f \u043a\u0430\u0436\u0434\u043e\u0433\u043e \u0430\u043a\u0442\u043e\u0440\u0430 \u0443\u043f\u043e\u0440\u044f\u0434\u043e\u0447\u0438\u0432\u0430\u044e\u0442 \u0432\u0441\u0435 \u0432\u0445\u043e\u0434\u044f\u0449\u0438\u0435 \u0437\u0430\u043f\u0440\u043e\u0441\u044b, \u0447\u0442\u043e \u0434\u0430\u0435\u0442 \u043f\u043e\u0441\u043b\u0435\u0434\u043e\u0432\u0430\u0442\u0435\u043b\u044c\u043d\u043e\u0441\u0442\u044c \u0432\u044b\u043f\u043e\u043b\u043d\u0435\u043d\u0438\u044f \u043a\u043e\u043c\u0430\u043d\u0434 \u0438 \u0442\u0430\u043a\u0436\u0435 \u043f\u043e\u0437\u0432\u043e\u043b\u044f\u0435\u0442 \u0438\u0437\u0431\u0435\u0436\u0430\u0442\u044c \u043f\u043e\u0431\u043e\u0447\u043d\u044b\u0445 \u044d\u0444\u0444\u0435\u043a\u0442\u043e\u0432 \u0432\u043b\u0438\u044f\u043d\u0438\u044f \u043d\u0430 \u0447\u043b\u0435\u043d\u044b \u043a\u043b\u0430\u0441\u0441\u0430 \u0430\u043a\u0442\u043e\u0440\u0430.  <\/p>\n<p>\u041e\u0431\u0449\u0430\u044f \u0441\u0445\u0435\u043c\u0430 \u0437\u0430\u043f\u0440\u043e\u0441\u043e\u0432 \u0431\u0443\u0434\u0435\u0442 \u0432\u044b\u0433\u043b\u044f\u0434\u0435\u0442\u044c \u043a\u0430\u043a  <a href=\"https:\/\/github.com\/qquser\/Akka.Jobs\/blob\/master\/Akka.Jobs\/Theater\/Master\/MasterActor.cs\" rel=\"noopener noreferrer nofollow\">MasterActor<\/a>\u2192 <a href=\"https:\/\/github.com\/qquser\/Akka.Jobs\/blob\/master\/Akka.Jobs\/Theater\/Master\/Groups\/GroupActor.cs\" rel=\"noopener noreferrer nofollow\">GroupActor<\/a> \u2192 <a href=\"https:\/\/github.com\/qquser\/Akka.Jobs\/blob\/master\/Akka.Jobs\/Theater\/Master\/Groups\/Workers\/ManagerActor.cs\" rel=\"noopener noreferrer nofollow\">ManagerActor<\/a> \u2192 <a href=\"https:\/\/github.com\/qquser\/Akka.Jobs\/blob\/master\/Akka.Jobs\/Theater\/Master\/Groups\/Workers\/WorkerActor.cs\" rel=\"noopener noreferrer nofollow\">WorkerActor<\/a><\/p>\n<h2>MasterActor <\/h2>\n<p>\u041e\u043f\u0440\u0435\u0434\u0435\u043b\u0438\u043c \u0442\u043e\u0447\u043a\u0443 \u0432\u0445\u043e\u0434\u0430 \u0432 \u0441\u0438\u0441\u0442\u0435\u043c\u0443 \u0430\u043a\u0442\u043e\u0440\u043e\u0432 \u2014 \u044d\u0442\u043e \u0431\u0443\u0434\u0435\u0442 <a href=\"https:\/\/github.com\/qquser\/Akka.Jobs\/blob\/master\/Akka.Jobs\/Theater\/Master\/MasterActor.cs\" rel=\"noopener noreferrer nofollow\">MasterActor<\/a>.<\/p>\n<p>\u0415\u0433\u043e \u0437\u0430\u0434\u0430\u0447\u0430\u043c\u0438 \u044f\u0432\u043b\u044f\u0435\u0442\u0441\u044f \u0434\u043e\u0441\u0442\u0430\u0432\u043a\u0430 \u0441\u043e\u043e\u0431\u0449\u0435\u043d\u0438\u0439 \u0434\u043e \u0441\u0432\u043e\u0438\u0445 \u0434\u043e\u0447\u0435\u0440\u043d\u0438\u0445 \u0430\u043a\u0442\u043e\u0440\u043e\u0432 \u0438 \u043e\u043f\u0440\u0435\u0434\u0435\u043b\u0435\u043d\u0438\u0435 \u0441\u0442\u0440\u0430\u0442\u0435\u0433\u0438\u0438 \u043f\u0435\u0440\u0435\u0437\u0430\u043f\u0443\u0441\u043a\u0430 \u043f\u043e\u0434\u0447\u0438\u043d\u0435\u043d\u043d\u044b\u0445 \u044d\u043b\u0435\u043c\u0435\u043d\u0442\u043e\u0432 \u0432 \u0441\u043b\u0443\u0447\u0430\u0435 \u043e\u0448\u0438\u0431\u043a\u0438.  <\/p>\n<p>\u0414\u043b\u044f \u043e\u0442\u043f\u0440\u0430\u0432\u043a\u0438 \u0441\u043e\u043e\u0431\u0449\u0435\u043d\u0438\u0439 \u0438\u0437 \u0432\u043d\u0435\u0448\u043d\u0438\u0445 \u0438\u0441\u0442\u043e\u0447\u043d\u0438\u043a\u043e\u0432, \u043a\u043e\u0442\u043e\u0440\u044b\u0435 \u043d\u0435 \u043d\u0430\u0445\u043e\u0434\u044f\u0442\u0441\u044f \u0432 \u0441\u0438\u0441\u0442\u0435\u043c\u0435 \u0430\u043a\u0442\u043e\u0440\u043e\u0432 ActorSystem (\u0437\u0434\u0435\u0441\u044c \u044d\u0442\u043e <a href=\"https:\/\/github.com\/qquser\/Akka.Jobs\/blob\/master\/Akka.Jobs\/Services\/JobContext.cs\" rel=\"noopener noreferrer nofollow\">JobContext<\/a>) \u0438\u0441\u043f\u043e\u043b\u044c\u0437\u0443\u0435\u0442\u0441\u044f \u043a\u043e\u043c\u0430\u043d\u0434\u0430 \u043e\u0436\u0438\u0434\u0430\u043d\u0438\u044f \u043e\u0442\u0432\u0435\u0442\u0430 &#8212;  Ask.<\/p>\n<pre><code class=\"cs\">await _masterActor.Ask&lt;JobCreatedCommandResult>(command, currentTimeout);<\/code><\/pre>\n<p>Ask \u043e\u0436\u0438\u0434\u0430\u0435\u0442 \u043e\u0442\u0432\u0435\u0442\u0430 \u043e\u0442 \u043c\u043e\u0434\u0435\u043b\u0438 \u0430\u043a\u0442\u043e\u0440\u043e\u0432 <code>JobCreatedCommandResult<\/code>, \u0434\u043b\u044f \u0437\u0430\u0434\u0430\u043d\u043d\u043e\u0433\u043e \u043f\u0440\u043e\u043c\u0435\u0436\u0443\u0442\u043a\u0430 \u0432\u0440\u0435\u043c\u0435\u043d\u0438  currentTimeout. \u0413\u0434\u0435 \u043a\u043e\u043c\u0430\u043d\u0434\u0430 \u0438\u043c\u0435\u0435\u0442 \u0442\u0438\u043f <code>DoJobCommand<\/code> \u0438 \u043f\u0440\u0438\u043d\u0438\u043c\u0430\u0435\u0442\u0441\u044f  <a href=\"https:\/\/github.com\/qquser\/Akka.Jobs\/blob\/master\/Akka.Jobs\/Theater\/Master\/MasterActor.cs\" rel=\"noopener noreferrer nofollow\">MasterActor<\/a> \u043c\u0435\u0442\u043e\u0434\u043e\u043c  <code>Receive<\/code>, \u0437\u0430\u0434\u0430\u043d\u043d\u043e\u043c \u0432 \u043a\u043e\u043d\u0441\u0442\u0440\u0443\u043a\u0442\u043e\u0440\u0435.<\/p>\n<ul>\n<li>\n<p> <code>DoJobCommandHandler<\/code> &#8212; \u043c\u0435\u0442\u043e\u0434, \u043a\u043e\u0442\u043e\u0440\u044b\u0439 \u043f\u0435\u0440\u0435\u0434\u0430\u0441\u0442 \u0441\u043e\u043e\u0431\u0449\u0435\u043d\u0438\u0435 \u0441\u0443\u0449\u0435\u0441\u0442\u0432\u0443\u044e\u0449\u0435\u043c\u0443 \u0433\u0440\u0443\u043f\u043f\u043e\u0432\u043e\u043c\u0443 \u0430\u043a\u0442\u043e\u0440\u0443 \u0438\u043b\u0438 \u0441\u043e\u0437\u0434\u0430\u0441\u0442 \u0435\u0433\u043e \u043d\u043e\u0432\u044b\u0439 \u044d\u043a\u0437\u0435\u043c\u043f\u043b\u044f\u0440 \u0432 \u0441\u043b\u0443\u0447\u0430\u0435 \u043e\u0442\u0441\u0443\u0442\u0441\u0432\u0438\u044f \u0441 \u0441\u043e\u0437\u0440\u0430\u043d\u0435\u043d\u0438\u0435\u043c \u0441\u0441\u044b\u043b\u043a\u0438 IActorRef \u043d\u0430 \u043d\u0435\u0433\u043e.<\/p>\n<\/li>\n<\/ul>\n<ul>\n<li>\n<p><code>StopJobCommandHandler<\/code> &#8212; \u043c\u0435\u0442\u043e\u0434 \u0432\u044b\u0437\u044b\u0432\u0430\u0435\u043c\u044b\u0439 \u0432 \u043c\u043e\u043c\u0435\u043d\u0442 \u0437\u0430\u043f\u0440\u043e\u0441\u0430 \u043d\u0430 \u043e\u0441\u0442\u0430\u043d\u043e\u0432\u043a\u0443 \u0432\u043e\u0440\u043a\u0435\u0440\u0430.<\/p>\n<\/li>\n<li>\n<p><code>RequestAllWorkersInfoQueryHandler<\/code> &#8212; \u0445\u0435\u043d\u0434\u043b\u0435\u0440 \u0437\u0430\u043f\u0440\u043e\u0441\u043e\u0432 \u0441\u043e\u0441\u0442\u043e\u044f\u043d\u0438\u044f \u0433\u0440\u0443\u043f\u043f\u044b \u0430\u043a\u0442\u043e\u0440\u043e\u0432 \u043e\u043f\u0440\u0435\u0434\u0435\u043b\u0435\u043d\u043d\u043e\u0433\u043e \u0442\u0438\u043f\u0430 IJob <\/p>\n<\/li>\n<\/ul>\n<pre><code class=\"cs\">internal class MasterActor&lt;TIn, TOut> : ReceiveActor     where TIn : IJobInput     where TOut : IJobResult {      private readonly Dictionary&lt;string, IActorRef> _groupIdToActor = new();     private readonly Dictionary&lt;IActorRef, string> _actorToGroupId = new();      public MasterActor()     {         \/\/Commands         Receive&lt;DoJobCommand&lt;TIn>>(DoJobCommandHandler);         Receive&lt;StopJobCommand>(StopJobCommandHandler);          \/\/Queries         Receive&lt;RequestAllWorkersInfo>(RequestAllWorkersInfoQueryHandler);      }       private void DoJobCommandHandler(DoJobCommand&lt;TIn> doJobCommand)     {          if (_groupIdToActor.TryGetValue(doJobCommand.GroupName, out var actorRef))         {             actorRef.Forward(doJobCommand);             return;         }          var groupActorProps = DependencyResolver             .For(Context.System)             .Props&lt;GroupActor&lt;TIn,TOut>>();          var groupActor = Context             .ActorOf(groupActorProps, $\"group-{doJobCommand.GroupName}\");          Context.Watch(groupActor);          groupActor.Forward(doJobCommand);          _groupIdToActor.Add(doJobCommand.GroupName, groupActor);         _actorToGroupId.Add(groupActor, doJobCommand.GroupName);      }      private void StopJobCommandHandler(StopJobCommand command)     {         if (!_groupIdToActor.ContainsKey(command.GroupName))         {             Sender.Tell(new StopJobCommandResult(false, $\"Group Actor list does not contain {command.GroupName}\"));             return;         }          _groupIdToActor[command.GroupName].Forward(command);     } ...<\/code><\/pre>\n<h2>GroupActor <\/h2>\n<p>DoJobCommandHandler \u0434\u043e\u043b\u0436\u0435\u043d \u0441\u043e\u0437\u0434\u0430\u0442\u044c \u0434\u043e\u0447\u0435\u0440\u043d\u0438\u0439 \u0430\u043a\u0442\u043e\u0440 <a href=\"https:\/\/github.com\/qquser\/Akka.Jobs\/blob\/master\/Akka.Jobs\/Theater\/Master\/Groups\/GroupActor.cs\" rel=\"noopener noreferrer nofollow\">GroupActor<\/a>, \u043a\u043e\u0442\u043e\u0440\u044b\u0439 \u043e\u043f\u0438\u0448\u0435\u0442 \u0433\u0440\u0443\u043f\u043f\u0443 \u0432\u044b\u043f\u043e\u043b\u043d\u044f\u0435\u043c\u044b\u0445 \u0437\u0430\u0434\u0430\u0447. \u0415\u0433\u043e \u0444\u0443\u043d\u043a\u0446\u0438\u044f \u043f\u0440\u043e\u0441\u0442\u0430, \u043e\u043d \u0434\u043e\u043b\u0436\u0435\u043d \u043f\u0435\u0440\u0435\u0434\u0430\u0432\u0430\u0442\u044c \u0441\u043e\u043e\u0431\u0449\u0435\u043d\u0438\u044f \u0443\u043f\u0440\u0430\u0432\u043b\u0435\u043d\u0446\u0430\u043c \u0440\u0430\u0431\u043e\u0447\u0438\u0445 \u0438 \u0441\u043e\u0445\u0440\u0430\u043d\u044f\u0442\u044c \u0441\u0441\u044b\u043b\u043a\u0438 \u043d\u0430 \u0434\u043e\u0447\u0435\u0440\u043d\u0438\u0435 \u0430\u043a\u0442\u043e\u0440\u044b \u0434\u043b\u044f \u043f\u0440\u0435\u0434\u043e\u0441\u0442\u0430\u0432\u043b\u0435\u043d\u0438\u044f \u0432 \u0434\u0430\u043b\u044c\u043d\u0435\u0439\u0448\u0435\u043c \u0432\u043e\u0437\u043c\u043e\u0436\u043d\u043e\u0441\u0442\u0438 \u043e\u0431\u0440\u0430\u0442\u0438\u0442\u044c\u0441\u044f \u043a \u0438\u0445 \u0441\u043e\u0441\u0442\u043e\u044f\u043d\u0438\u044e. <\/p>\n<ul>\n<li>\n<p><code>TrySaveWorkerActorRefCommand<\/code> &#8212; \u0441\u043e\u043e\u0431\u0449\u0435\u043d\u0438\u0435 \u043a\u043e\u0442\u043e\u0440\u043e\u0435 \u043f\u0435\u0440\u0435\u0434\u0430\u0435\u0442\u0441\u044f \u043e\u0442 workerActor \u0434\u043b\u044f \u0441\u043e\u0445\u0440\u0430\u043d\u0435\u043d\u0438\u044f \u0441\u0441\u044b\u043b\u043a\u0438 IActorRef \u0432 \u0433\u0440\u0443\u043f\u043f\u043e\u0432\u043e\u043c \u0430\u043a\u0442\u043e\u0440\u0435.<\/p>\n<\/li>\n<li>\n<p><code>ManagerActorTerminatedHandler<\/code> &#8212; \u0432\u044b\u0437\u044b\u0432\u0430\u0435\u0442\u0441\u044f \u043f\u043e\u0441\u043b\u0435 \u043e\u0441\u0442\u0430\u043d\u043e\u0432\u043a\u0438 <code>ManagerActor<\/code> \u0438 \u0443\u0434\u0430\u043b\u044f\u0435\u0442 \u0441\u0441\u044b\u043b\u043a\u0438 \u043d\u0430 \u043e\u0431\u044a\u0435\u043a\u0442\u044b <code>IActorRef<\/code> \u0434\u043b\u044f <code>ManagerActor<\/code> \u0438 <code>WorkerActor<\/code>.<\/p>\n<\/li>\n<\/ul>\n<pre><code class=\"cs\">internal class GroupActor&lt;TIn, TOut> : ReceiveActor     where TIn : IJobInput     where TOut : IJobResult {      private string? _groupId;      private readonly Dictionary&lt;Guid, IActorRef> _idToManagerActor = new();     private readonly Dictionary&lt;IActorRef, Guid> _managerActorToId = new();      private readonly Dictionary&lt;IActorRef, Guid> _workerActorToId = new();     private readonly Dictionary&lt;Guid, IActorRef> _idToWorkerActor = new();        public GroupActor()     {         \/\/Commands         Receive&lt;DoJobCommand&lt;TIn>>(DoJobCommandHandler);         Receive&lt;StopJobCommand>(StopJobCommandHandler);          \/\/Queries         Receive&lt;RequestAllWorkersInfo>(RequestAllWorkersInfoQueryHandler);          \/\/Internal         Receive&lt;TrySaveWorkerActorRefCommand>(TrySaveWorkerActorRefCommandHandler);         Receive&lt;Terminated>(ManagerActorTerminatedHandler);      }      private void DoJobCommandHandler(DoJobCommand&lt;TIn> doJobCommand)     {         if (_groupId != null &amp;&amp; doJobCommand.GroupName != _groupId)         {             var message = \"Ignoring Create Worker Actor\";             Sender.Tell(doJobCommand.IsCreateCommand                     ? new JobCreatedCommandResult(false, message, doJobCommand.JobId)                     : new JobDoneCommandResult(false, message, doJobCommand.JobId));             return;         }          if (_idToManagerActor.ContainsKey(doJobCommand.JobId))         {             var message = $\"{doJobCommand.JobId} Actor Exists.\";             Sender.Tell(doJobCommand.IsCreateCommand                 ? new JobCreatedCommandResult(false, message, doJobCommand.JobId)                 : new JobDoneCommandResult(false, message, doJobCommand.JobId));             return;         }          _groupId ??= doJobCommand.GroupName;          var managerActorProps = DependencyResolver             .For(Context.System)             .Props&lt;ManagerActor&lt;TIn,TOut>>();                  var managerActor = Context.ActorOf(managerActorProps,             $\"manager-{doJobCommand.JobId}\");          Context.Watch(managerActor);          _idToManagerActor.Add(doJobCommand.JobId, managerActor);         _managerActorToId.Add(managerActor, doJobCommand.JobId);         managerActor.Forward(doJobCommand);     }      private void ManagerActorTerminatedHandler(Terminated t)     {         var workerId = _managerActorToId[t.ActorRef];         _managerActorToId.Remove(t.ActorRef);         _idToManagerActor.Remove(workerId);          if (!_idToWorkerActor.TryGetValue(workerId, out var workerActorRef))             return;         _workerActorToId.Remove(workerActorRef);         _idToWorkerActor.Remove(workerId);     } ...<\/code><\/pre>\n<h2>ManagerActor<\/h2>\n<p>\u0421 \u043f\u043e\u0432\u0435\u0434\u0435\u043d\u0438\u0435\u043c <a href=\"https:\/\/github.com\/qquser\/Akka.Jobs\/blob\/master\/Akka.Jobs\/Theater\/Master\/Groups\/Workers\/ManagerActor.cs\" rel=\"noopener noreferrer nofollow\">ManagerActor<\/a> \u0434\u0435\u043b\u0430 \u043e\u0431\u0441\u0442\u043e\u044f\u0442 \u0447\u0443\u0442\u044c \u0441\u043b\u043e\u0436\u043d\u0435\u0435, \u0435\u043c\u0443 \u043d\u0435\u043e\u0431\u0445\u043e\u0434\u0438\u043c\u043e \u043e\u043f\u0440\u0435\u0434\u0435\u043b\u0438\u0442\u044c \u0441\u0442\u0440\u0430\u0442\u0435\u0433\u0438\u044e \u043f\u043e\u0432\u0435\u0434\u0435\u043d\u0438\u044f \u043f\u0440\u0438 \u0432\u043e\u0437\u043d\u0438\u043a\u043d\u043e\u0432\u0435\u043d\u0438\u0438 \u043e\u0448\u0438\u0431\u043e\u043a \u0443 \u0440\u0430\u0431\u043e\u0447\u0435\u0433\u043e  <a href=\"https:\/\/github.com\/qquser\/Akka.Jobs\/blob\/master\/Akka.Jobs\/Theater\/Master\/Groups\/Workers\/WorkerActor.cs\" rel=\"noopener noreferrer nofollow\">WorkerActor<\/a>, \u0438 \u0441\u043e\u0445\u0440\u0430\u043d\u0438\u0442\u044c \u043d\u0430\u0447\u0430\u043b\u044c\u043d\u044b\u0439 \u0437\u0430\u043f\u0440\u043e\u0441 \u00ab<a href=\"https:\/\/github.com\/qquser\/Akka.Jobs\/blob\/master\/Akka.Jobs\/Theater\/Master\/Groups\/Workers\/Messages\/WorkerDoJobCommand.cs\" rel=\"noopener noreferrer nofollow\">WorkerDoJobCommand<\/a>\u00bb \u0434\u043b\u044f \u043f\u043e\u0432\u0442\u043e\u0440\u043d\u044b\u0445 \u043e\u0442\u043f\u0440\u0430\u0432\u043e\u043a \u044d\u0442\u043e\u0433\u043e \u0437\u0430\u043f\u0440\u043e\u0441\u0430 \u0432 \u043c\u043e\u043c\u0435\u043d\u0442\u044b \u043f\u0435\u0440\u0435\u0437\u0430\u043f\u0443\u0441\u043a\u0430. <\/p>\n<pre><code class=\"cs\">internal class ManagerActor&lt;TIn, TOut> : ReceiveActor     where TIn : IJobInput     where TOut : IJobResult  {     \/\/\u041f\u0430\u0440\u0430\u043c\u0435\u0442\u0440\u044b \u0441\u0442\u0440\u0430\u0442\u0435\u0433\u0438\u0438 \u043f\u0435\u0440\u0435\u0437\u0430\u043f\u0443\u0441\u043a\u0430     private int _currentNrOfRetries;     private int _maxNrOfRetries;     private TimeSpan _minBackoff;     private TimeSpan _maxBackoff;      \/\/\u0421\u0441\u044b\u043b\u043a\u0430 \u043d\u0430 \u043e\u0442\u043f\u0440\u0430\u0432\u0438\u0442\u0435\u043b\u044c \u043a\u043e\u043c\u0430\u043d\u0434\u044b \u043d\u0430 \u0432\u044b\u043f\u043e\u043b\u043d\u0435\u043d\u0438\u0435 \u0440\u0430\u0431\u043e\u0442\u044b     private IActorRef? _doJobCommandSender;     \/\/BackoffSupervisor     private IActorRef? _workerSupervisorActor;     \/\/\u041a\u043e\u043c\u0430\u043d\u0434\u0430 \u0434\u043b\u044f \u0434\u043e\u0447\u0435\u0440\u043d\u0435\u0433\u043e \u0430\u043a\u0442\u043e\u0440\u0430 \u0434\u043b\u044f \u043f\u043e\u0432\u0442\u043e\u0440\u043d\u043e\u0439 \u043e\u0442\u043f\u0440\u0430\u0432\u043a\u0438 \u0432 \u043c\u043e\u043c\u0435\u043d\u0442 \u0440\u0435\u0441\u0442\u0430\u0440\u0442\u043e\u0432     private WorkerDoJobCommand&lt;TIn>? _doJobCommand;      private Guid _jobId;     private bool _startedFlag;      \/\/StopJobCommandHandler \u043f\u0435\u0440\u0435\u0434\u0430\u043d\u043d\u044b\u0439 \u043e\u0442 JobContext \u0432\u044b\u0437\u043e\u0432\u0435\u0442 \u043e\u0442\u043c\u0435\u043d\u0443 \u0437\u0430\u0434\u0430\u0447\u0438     private readonly CancellationTokenSource _cancellationTokenSource = new ();      private readonly ILogger&lt;ManagerActor&lt;TIn, TOut>> _logger;      public ManagerActor(ILogger&lt;ManagerActor&lt;TIn, TOut>> logger)     {         _logger = logger;          \/\/Commands          Receive&lt;DoJobCommand&lt;TIn>>(DoJobCommandHandler);         Receive&lt;StopJobCommand>(StopJobCommandHandler);          \/\/Queries          Receive&lt;ReadWorkerInfoCommand>(ReadWorkerInfoCommandHandler);      <\/code><\/pre>\n<\/div>\n<\/div>\n<\/div>\n<\/div>\n","protected":false},"author":1,"featured_media":0,"comment_status":"open","ping_status":"open","sticky":false,"template":"","format":"standard","meta":{"footnotes":""},"categories":[],"tags":[],"class_list":["post-348601","post","type-post","status-publish","format-standard","hentry"],"_links":{"self":[{"href":"https:\/\/savepearlharbor.com\/index.php?rest_route=\/wp\/v2\/posts\/348601","targetHints":{"allow":["GET"]}}],"collection":[{"href":"https:\/\/savepearlharbor.com\/index.php?rest_route=\/wp\/v2\/posts"}],"about":[{"href":"https:\/\/savepearlharbor.com\/index.php?rest_route=\/wp\/v2\/types\/post"}],"author":[{"embeddable":true,"href":"https:\/\/savepearlharbor.com\/index.php?rest_route=\/wp\/v2\/users\/1"}],"replies":[{"embeddable":true,"href":"https:\/\/savepearlharbor.com\/index.php?rest_route=%2Fwp%2Fv2%2Fcomments&post=348601"}],"version-history":[{"count":0,"href":"https:\/\/savepearlharbor.com\/index.php?rest_route=\/wp\/v2\/posts\/348601\/revisions"}],"wp:attachment":[{"href":"https:\/\/savepearlharbor.com\/index.php?rest_route=%2Fwp%2Fv2%2Fmedia&parent=348601"}],"wp:term":[{"taxonomy":"category","embeddable":true,"href":"https:\/\/savepearlharbor.com\/index.php?rest_route=%2Fwp%2Fv2%2Fcategories&post=348601"},{"taxonomy":"post_tag","embeddable":true,"href":"https:\/\/savepearlharbor.com\/index.php?rest_route=%2Fwp%2Fv2%2Ftags&post=348601"}],"curies":[{"name":"wp","href":"https:\/\/api.w.org\/{rel}","templated":true}]}}