0%

[DotnetCore]排程利器-Coravel:Queue篇

前提情要

筆者上篇介紹完CoravelScheduler功能後,這篇要來實作Queue的功能了,筆者敘述一下工作上用到的情境,最近因大系統要上線,必須實作Data Migration,為方便,不防做一個前端頁面,才可以有介面去點擊執行Data Migration作業,想當然爾,作業時間一定無法在一個Request時間內完成,一定會噴Timeout Error

再則為這點小功能,不想透過HangfireBackgroundJob.Enqueue來實作,這時想到Coravel也有提供Queue功能,API站台的action收到Data Migration的request後,塞入一則CoravelQueue,由Queue對應的Service去往下執行對應的作業,是個完美的方案吧。

內容

安裝Coravel套件

1
dotnet add package coravel

註冊Coravel的Queue服務

首先必須於Startup.cs中註冊Queue

1
2
3
4
5
public void ConfigureServices(IServiceCollection services)
{
// 以上省略
services.AddQueue();
}

建構值注入IQueue

1
2
3
4
5
IQueue _queue;

public HomeController(IQueue queue) {
this._queue = queue;
}

QueueJob宣告

QueueJob

QueueJob與Scheduler一樣,需要實作IInvocable

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
public class LogQueueJob : IInvocable
{
private readonly IHostEnvironment _env;
private readonly IConfiguration _config;

public LogQueueJob(IHostEnvironment env, IConfiguration config)
{
_env = env;
_config = config;
}

public Task Invoke()
{
Console.WriteLine(
$"[QueueuService {DateTime.Now.ToString("yyyy/MM/dd HH:mm:ss")}]: {_env.ContentRootPath}");
return Task.CompletedTask;
}
}

QueueJobWithPayload

為了示範PayLoad傳送,宣告一個Class

1
2
3
4
public class UserModel
{
public string UserName { get; set; }
}

因為需要做序列化成字串輸出,安裝老牌子序列化套件Json.NET

1
dotnet add package Newtonsoft.Json

筆者就沿用Coravel那篇的Log形式

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
public class LogQueueJobWithPayLoad : IInvocable, IInvocableWithPayload<UserModel>
{
private readonly IHostEnvironment _env;
private readonly IConfiguration _config;
public UserModel Payload { get; set; }

public LogQueueJobWithPayLoad(IHostEnvironment env, IConfiguration config)
{
_env = env;
_config = config;
}

public Task Invoke()
{
Console.WriteLine($"Payload: {JsonConvert.SerializeObject(Payload)}");
Console.WriteLine(
$"[QueueServiceWithPayload {DateTime.Now.ToString("yyyy/MM/dd HH:mm:ss")}]: {_env.ContentRootPath}");
return Task.CompletedTask;
}
}

其中比LogQueueJob多了一個實作IInvocableWithPayload<T>,該T為要傳輸的Model型別,筆者這邊使用前一步宣告好的UserModel,再則需要宣告一個同樣T型別的參數,並且名為Payload,就大功告成了。

執行QueueJob

QueueJob註冊

筆者上篇也有提醒過,Coravel也是透過Dotnet Core的DI機制,取得QueueJob並執行,因此需要將QueueJob做註冊的動作

1
2
3
4
5
6
7
public void ConfigureServices(IServiceCollection services)
{
// 以上省略
services.AddQueue();
services.AddTransient<LogQueueJob>();
services.AddTransient<LogQueueJobWithPayLoad>();
}

撰寫Demo Action

分別為api/home/queue以及api/home/queuewithpayload

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
/// <summary>
/// QueueJob示範
/// </summary>
/// <returns></returns>
[HttpPost("queue")]
public IActionResult InvocableQueueJob()
{
_queue.QueueInvocable<LogQueueJob>();
return Ok("");
}

/// <summary>
/// QueueJobWithPayload示範
/// </summary>
/// <returns></returns>
[HttpPost("queuewithPayload")]
public IActionResult InvocableQueueJobWithPayload()
{
var userModel = new UserModel()
{
UserName = "Eugene Su"
};
_queue.QueueInvocableWithPayload<LogQueueJobWithPayLoad, UserModel>(userModel);
return Ok("");
}

執行結果

筆者使用單純的dotnet run指令來啟動API站台

1
dotnet run

打開Postman,輸入http://localhost:5000/api/home/queuehttp method選擇Post

再則我們在command line畫面看輸出

再來試Payload部份,調整一下Postman中的url,結尾改為queuewithpayload

command line看輸出

可以從結果看出將payload序列化後輸出的結果,也正常輸出時間以及environmentcontentrootpath

結論

若有一些作業是不需要馬上回應,只要背景作業,筆者認為CoravelQueue功能不失為一個選項,簡單設定,符合dotnet core的DI機制,簡單上手,推薦給大家。

參考

https://docs.coravel.net/Queuing/