<output id="qn6qe"></output>

    1. <output id="qn6qe"><tt id="qn6qe"></tt></output>
    2. <strike id="qn6qe"></strike>

      亚洲 日本 欧洲 欧美 视频,日韩中文字幕有码av,一本一道av中文字幕无码,国产线播放免费人成视频播放,人妻少妇偷人无码视频,日夜啪啪一区二区三区,国产尤物精品自在拍视频首页,久热这里只有精品12

      ABP框架理論學習之后臺工作(Jobs)和后臺工作者(Workers)

      返回總目錄


      本篇目錄

      介紹

      ABP提供了后臺工作和后臺工作者,它們會在應用程序的后臺線程中執行一些任務。

      后臺工作

      后臺工作以隊列和持續的方式在后臺給一些即將被執行的任務排隊。你可能因為某些原因需要后臺工作,比如:

      • 執行長時間運行的任務。比如,一個用戶按了“report”按鈕來啟動一個長時間運行的報告工作,點擊了這個按鈕你不可能讓用戶一直處于等待狀態,所以你應該將這個工作(job)添加到 隊列(queue)中,然后,當這項工作完成時,通過郵件將報告結果發送給該用戶。
      • 創建重復嘗試(re-trying)和持續的任務來保證代碼將會 成功執行。比如,你可以在后臺工作中發送郵件以克服 臨時失敗,并 保證郵件最終能夠發送出去。因此,當發送郵件的時候用戶不需要等待。

      創建一個后臺工作

      我們可以通過繼承BackgroundJob類或者直接實現 IBackgroundJob接口來創建一個后臺工作類。

      下面是一個最簡單的后臺工作:

      public class TestJob : BackgroundJob<int>, ITransientDependency
      {
          public override void Execute(int number)
          {
              Logger.Debug(number.ToString());
          }
      }
      
      

      該后臺工作定義了一個需要輸入參數的Execute方法。參數類型是泛型參數類型。

      后臺工作必須注冊到依賴注入系統中,實現ITransientDependency是最簡單的方式。

      接下來定義一個更現實的工作,它會在后臺隊列中發送郵件:

      public class SimpleSendEmailJob : BackgroundJob<SimpleSendEmailJobArgs>, ITransientDependency
      {
          private readonly IRepository<User, long> _userRepository;
          private readonly IEmailSender _emailSender;
      
          public SimpleSendEmailJob(IRepository<User, long> userRepository, IEmailSender emailSender)
          {
              _userRepository = userRepository;
              _emailSender = emailSender;
          }
      
          public override void Execute(SimpleSendEmailJobArgs args)
          {
              var senderUser = _userRepository.Get(args.SenderUserId);
              var targetUser = _userRepository.Get(args.TargetUserId);
      
              _emailSender.Send(senderUser.EmailAddress, targetUser.EmailAddress, args.Subject, args.Body);
          }
      }
      
      

      我們注入了user倉儲(為了獲得用戶信息)和email發送者(發送郵件的服務),然后簡單地發送了該郵件。SimpleSendEmailJobArgs是該工作的參數,它定義如下:

      [Serializable]
      public class SimpleSendEmailJobArgs
      {
          public long SenderUserId { get; set; }
      
          public long TargetUserId { get; set; }
      
          public string Subject { get; set; }
      
          public string Body { get; set; }
      }
      
      

      工作參數應該是serializable(可序列化),因為要將它 序列化并存儲到數據庫中。雖然ABP默認的后臺工作管理者使用了JSON序列化(它不需要[Serializable]特性),但是最好定義 [Serializable]特性,因為我們將來可能會轉換到其他使用二進制序列化的工作管理者。

      記住,要保持你的參數簡單,不要在參數中包含實體或者其他非可序列化的對象。正如上面的例子演示的那樣,我們只存儲了實體的 Id,然后在該工作的內部從倉儲中獲得該實體。

      添加新工作到隊列

      當定義了一個后臺工作后,我們就可以注入并使用IBackgroundJobManager來添加一個工作到隊列中。看上面定義的TestJob的例子:

      public class MyService
      {
          private readonly IBackgroundJobManager _backgroundJobManager;
      
          public MyService(IBackgroundJobManager backgroundJobManager)
          {
              _backgroundJobManager = backgroundJobManager;
          }
      
          public void Test()
          {
              _backgroundJobManager.Enqueue<TestJob, int>(42);
          }
      }
      
      

      當入隊(Enqueue)時,我們將42作為參數傳遞。IBackgroundJobManager將會實例化并使用42作為參數執行TestJob。

      讓我們看一下如何為上面定義的SimpleSendEmailJob添加一個新的工作:

      [AbpAuthorize]
      public class MyEmailAppService : ApplicationService, IMyEmailAppService
      {
          private readonly IBackgroundJobManager _backgroundJobManager;
      
          public MyEmailAppService(IBackgroundJobManager backgroundJobManager)
          {
              _backgroundJobManager = backgroundJobManager;
          }
      
          public async Task SendEmail(SendEmailInput input)
          {
                  await _backgroundJobManager.EnqueueAsync<SimpleSendEmailJob, SimpleSendEmailJobArgs>(
                  new SimpleSendEmailJobArgs
                  {
                      Subject = input.Subject,
                      Body = input.Body,
                      SenderUserId = AbpSession.GetUserId(),
                      TargetUserId = input.TargetUserId
                  });
          }
      }
      
      

      Enqueu (或 EnqueueAsync)方法還有其他的參數,比如 priority和 delay(優先級和延遲)

      默認的后臺工作管理者

      IBackgroundJobManager默認是由BackgroundJobManager實現的。它可以被其他的后臺工作提供者替代(看后面的Hangfire集成)。關于默認的BackgroundJobManager一些信息如下:

      • 它是一個在單線程中以FIFO(First In First Out)工作的簡單工作隊列,使用 IBackgroundJobStore來持久化工作。
      • 它會重復嘗試執行工作,直到工作成功執行(不會拋出任何異常)或者超時。默認的超時是一個工作2天。
      • 當成功執行后,它會從存儲(數據庫)中刪除該工作。如果超時了,就會將該工作設置為 abandoned(廢棄的),并保留在數據庫中。
      • 在重復嘗試一個工作之間會增加等待時間。第一次重試時等待1分鐘,第二次等待2分鐘,第三次等待4分鐘等等。
      • 在固定的時間間隔輪詢工作的存儲。查詢工作時先按優先級排序,再按嘗試次數排序。

      后臺工作存儲
      默認的BackgroundJobManager需要一個數據存儲來保存、獲得工作。如果你沒有實現IBackgroundJobStore,那么它會使用 InMemoryBackgroundJobStore,它不會將工作持久化到數據庫中。你可以簡單地實現它來存儲工作到數據庫或者你可以使用module-zero,它已經實現了IBackgroundJobStore。

      如果你正在使用第三方的工作管理者(像Hangfire),那么不需要實現IBackgroundJobStore。

      配置

      你可以在模塊的PreInitialize方法中使用Configuration.BackgroundJobs來配置后臺工作系統。

      關閉工作執行功能
      你可能想關閉應用程序的后臺工作執行:

      public class MyProjectWebModule : AbpModule
      {
          public override void PreInitialize()
          {
              Configuration.BackgroundJobs.IsJobExecutionEnabled = false;
          }
      
          //...
      }
      
      

      這種情況很罕見,但是想一下,如果你正在對相同的數據庫運行多個應用的實例(在web應用中)。在這種情況下,每個應用都會為工作查詢相同的數據庫并執行它們。這會導致相同工作的多次執行和一些其它問題。要阻止這種情況發生,你有兩種選擇:

      • 你可以只為該應用的一個實例開啟工作執行。
      • 你可以為該web應用的所有實例關閉工作執行,然后創建一個會執行后臺工作的獨立應用(比如一個Windows服務)。

      Hangfire集成

      后臺工作管理者設計成了可以被其他的后臺工作管理者取代。查看Hangfire集成來替代默認的后臺工作管理者。

      后臺工作者

      后臺工作者不同于后臺工作。它們是運行在應用后臺的簡單獨立線程。一般來說,它們會定期地執行一些任務。比如:

      • 后臺工作者可以定期運行來刪除舊的日志
      • 后臺工作者可以定期運行來確定不活躍的用戶,并給他們發送郵件以使他們返回你的應用。

      創建后臺工作者

      要創建后臺工作者,我們應該實現IBackgroundWorker接口。除此之外,我們可以基于需求從 BackgroundWorkerBase或者 PeriodicBackgroundWorkerBase繼承。

      假設一個用戶在過去30天內沒有登錄到該應用,那我們想要讓Ta的狀態為passive。看下面的代碼:

      public class MakeInactiveUsersPassiveWorker : PeriodicBackgroundWorkerBase, ISingletonDependency
      {
          private readonly IRepository<User, long> _userRepository;
      
          public MakeInactiveUsersPassiveWorker(AbpTimer timer, IRepository<User, long> userRepository)
              : base(timer)
          {
              _userRepository = userRepository;
              Timer.Period = 5000; //5 seconds (good for tests, but normally will be more)
          }
      
          [UnitOfWork]
          protected override void DoWork()
          {
              using (CurrentUnitOfWork.DisableFilter(AbpDataFilters.MayHaveTenant))
              {
                  var oneMonthAgo = Clock.Now.Subtract(TimeSpan.FromDays(30));
      
                  var inactiveUsers = _userRepository.GetAllList(u =>
                      u.IsActive &&
                      ((u.LastLoginTime < oneMonthAgo && u.LastLoginTime != null) || (u.CreationTime < oneMonthAgo && u.LastLoginTime == null))
                      );
      
                  foreach (var inactiveUser in inactiveUsers)
                  {
                      inactiveUser.IsActive = false;
                      Logger.Info(inactiveUser + " made passive since he/she did not login in last 30 days.");
                  }
      
                  CurrentUnitOfWork.SaveChanges();
              }
          }
      }
      
      

      這是現實中的代碼,并且在具有module-zero模塊的ABP中直接有效。

      • 如果你從PeriodicBackgroundWorkerBase 類繼承(如這個例子),那么你應該實現 DoWork方法來執行定期運行的代碼。
      • 如果從BackgroundWorkerBase繼承或直接實現了 IBackgroundWorker,那么你要重寫或者實現Start, Stop 和 WaitToStop方法。Start和Stop方法應該是 非阻塞的(non-blocking),WaitToStop方法應該等待工作者完成當前重要的工作。

      注冊后臺工作者

      創建一個后臺工作者后,我們應該把它添加到IBackgroundWorkerManager,通常放在模塊的PostInitialize方法中:

      public class MyProjectWebModule : AbpModule
      {
          //...
      
          public override void PostInitialize()
          {
              var workManager = IocManager.Resolve<IBackgroundWorkerManager>();
              workManager.Add(IocManager.Resolve<MakeInactiveUsersPassiveWorker>());
          }
      }
      
      

      雖然一般我們將工作者添加到PostInitialize方法中,但是沒有強制要求。你可以在任何地方注入IBackgroundWorkerManager,在運行時添加工作者。
      當應用要關閉時,IBackgroundWorkerManager會停止并釋放所有注冊的工作者。

      后臺工作者生命周期

      后臺工作者一般實現為單例的,但是沒有嚴格限制。如果你需要相同工作者類的多個實例,那么可以使它成為transient(每次使用時創建),然后給IBackgroundWorkerManager添加多個實例。在這種情況下,你的工作者很可能會參數化(比如,你有單個LogCleaner類,但是兩個LogCleaner工作者實例會監視并清除不同的log文件夾)。

      讓你的應用程序一直運行

      只有當你的應用運行時,后臺工作和工作者才會工作。如果一個Asp.Net 應用長時間沒有執行請求,那么它默認會關閉(shutdown)。如果你想讓后臺工作一直在web應用中執行(這是默認行為),那么你要確保web應用配置成了總是運行。否則,后臺工作只有在應用使用時才會執行。

      有很多技術來實現這個目的。最簡單的方法是從外部應用定期向你的web應用發送請求。這樣,你可以檢查web應用是否開啟并且處于運行狀態。Hangfire文檔講解了一些其他的方法。

      posted @ 2016-03-11 08:33  tkbSimplest  閱讀(18482)  評論(5)    收藏  舉報
      主站蜘蛛池模板: av偷拍亚洲一区二区三区| 免费av深夜在线观看| 国产95在线 | 欧美| 亚洲欧洲日韩精品在线| 亚洲国产高清第一第二区| 成人性做爰aaa片免费看| 99视频在线精品国自产拍| 上饶市| 亚洲激情一区二区三区视频| 高潮潮喷奶水飞溅视频无码| 熟妇人妻无码中文字幕老熟妇| 色老头亚洲成人免费影院| 精品无码一区二区三区电影| 亚洲精品一区二区18禁| 国产不卡一区在线视频| 黑人异族巨大巨大巨粗| 亚洲日韩精品一区二区三区| 蜜臀午夜一区二区在线播放| 99久久精品国产一区二区蜜芽| 亚洲人妻精品一区二区| 90后极品粉嫩小泬20p| 久久99九九精品久久久久蜜桃| 激情动态图亚洲区域激情| 国产一区二区三区AV在线无码观看| 乱人伦人妻中文字幕无码久久网 | 熟妇人妻系列aⅴ无码专区友真希| 日韩视频一区二区三区视频 | 粉嫩av一区二区三区蜜臀| 欧美成人片在线观看| 蜜臀av一区二区三区日韩| 午夜成人无码免费看网站| 国产精品中文字幕二区| 久久天天躁狠狠躁夜夜avapp | 隆化县| 激情综合五月丁香亚洲| 国内精品久久人妻无码网站| 超碰成人人人做人人爽| 国产高清无遮挡内容丰富| 少妇被粗大的猛烈进出动视频| 国产欧美在线手机视频| 国产精品亚洲综合网一区|