Sql-Server

通過 SQL 儲存過程創建 Hangfire 作業

  • May 22, 2021

我知道如何通過 .NET C# 程式碼創建 Hangfire 作業,但在某些情況下我希望數據庫觸發器執行 Hangfire 作業。我在網上搜尋但一無所獲,所以我嘗試編寫自己的儲存過程。

Hangfire 表位於 SQL Server 中,因此我假設我應該能夠通過將記錄插入正確的表來創建作業。

這不是一個簡單的過程,但我所做的是通過 C# 程式碼創建一個作業,研究 Hangfire 如何儲存數據,並編寫了一個儲存過程來完成同樣的事情。以下程式碼有效,但承認草率。

任何人都可以建議對此進行改進,或建議更好的儲存過程嗎?

   -- =============================================
   -- Author:      Gary Jorgenson, RN | robintek.com
   -- Create date: 3/23/2021
   -- Description: Create a Hangfire Job and Enqueue it
   -- =============================================
   ALTER PROCEDURE [dbo].[core_sp_CreateHangFireJob]
       @type AS VARCHAR(150) = NULL ,
       @Method AS VARCHAR(50) = NULL ,
       @AppCode AS VARCHAR(50) = NULL ,
       @Version AS VARCHAR(15) = NULL ,
       @Culture AS VARCHAR(50) = NULL ,
       @PublicKeyToken AS VARCHAR(50) = NULL ,
       @ParameterTypes AS VARCHAR(250) = NULL ,
       @Arguments AS VARCHAR(250) = NULL
   AS
   BEGIN

DECLARE @RandomString AS VARCHAR(MAX) = LOWER(RIGHT(CAST(NEWID() AS NVARCHAR(MAX)),8))

-- Build the JSON string Hangfire wants
DECLARE @InvocationData AS VARCHAR(2000) = 
'{"Type":"' + ISNULL(@type,'BackgroundJobs') + ', ' +
'App_Code.' + ISNULL(@AppCode, @RandomString) + ', ' +
'Version=' + ISNULL(@Version, '0.0.0.0') + ', ' +
'Culture=' + ISNULL(@Culture,'neutral') + ', ' +
'PublicKeyToken=' + ISNULL(@PublicKeyToken,'null') + '",' + 
'"Method":"' + ISNULL(@method,'UpdateActivityLog') + '","' +
'ParameterTypes":"' + ISNULL(@ParameterTypes,'[]') + '","' +
'Arguments":null}'

-- For some reason, Hangfire seems to set the inserted date/time as 4 hours ahead of actual time
DECLARE @inserted DATETIME = DATEADD(HOUR, 4, GETDATE());

-- Insert a record into Hangfire Job table. First of several inserts
INSERT INTO [dbo].[Job] 
   (
   [StateName] ,
   [InvocationData] ,
   [Arguments] ,
   [CreatedAt]
   )
   VALUES
   (
   'Enqueued' ,
   @InvocationData ,
   '['+ ISNULL( '"' + @Arguments + '"','') + ']',
   @inserted
   )

   -- Get the JobId as we'll need it for other inserts
   DECLARE @JobId AS BIGINT = IDENT_CURRENT('[dbo].[Job]');

   -- Break out date and time separately as well need to build
   -- a JSON string formatted properly for Hangfire
   DECLARE @insertedDate AS DATE = CONVERT(DATE, @inserted);
   DECLARE @insertedTime AS TIME = CONVERT(VARCHAR(10), @inserted, 108)

   DECLARE @EnqueuedAt AS VARCHAR(2000) = 
   '{"EnqueuedAt":"' +
   CONVERT(VARCHAR(20), @insertedDate) +
   'T'+ CONVERT(VARCHAR(20), @insertedTime) + 
   'Z","Queue":"default"}'

   -- Insert record into Hanfire state table showing this job
   -- as Enqueued
   INSERT INTO [dbo].[State]
          (
           [JobId] ,
           [Name] ,
           [Reason] ,
           [CreatedAt] ,
           [Data]
          )
    VALUES
          (
           @JobId ,
           'Enqueued',
           NULL ,
           @inserted ,
           @EnqueuedAt
          )

   -- Retrieve the new StateId as we have to update the job record with current StateId
   DECLARE @StateId AS BIGINT = scope_identity();

   UPDATE 
       [dbo].[Job]
   SET 
       StateId = @StateId
   WHERE
       id = @JobId

   -- Insert records into Hangfire JobParameter table showing the CurrentCulture
   INSERT INTO [dbo].[JobParameter]
      (
      [JobId] ,
      [Name] ,
      [Value]
      )
   VALUES
      (
      @JobId ,
      'CurrentCulture' ,
      '"en-US"'
      )

   -- Insert record into Hangfire JobParameter table showing the CurrentUICulture
   INSERT INTO [dbo].[JobParameter]
      (
      [JobId] ,
      [Name] ,
      [Value]
      )
   VALUES
      (
      @JobId ,
      'CurrentUICulture' ,
      '"en-US"'
      )

   -- Lastly, inserting the job Id into the Hangfire JobQueue table to start the job
   INSERT INTO [dbo].[JobQueue]
   (
       [JobId] ,
       [Queue] 
   )
   VALUES
   (   @JobId ,     -- JobId - bigint
       N'default'   -- Queue - nvarchar(50)
   )

   RETURN 1
   END

來自 Hangfire 網站

Hangfire 是一個開源框架,可幫助您創建、處理和管理後台作業,即您不想放入請求處理管道的操作。

它已成為 Web 應用程序開發人員管理後台作業的流行工具。在大多數情況下,Hangfire 作業是在應用程式碼中創建或設置為重複任務。

我最初計劃在 Stack Overflow 上發布這個問題,因為開發人員更可能熟悉 Hangfire。有人建議我在這裡發布更多面向 SQL 的問題。

在 Hangfire 網站上,我找不到任何支持對 SQL 數據庫進行外部修改的參考資料。所以我認為它不受支持。

當您直接修改數據庫時,您將跳過應用程序中實現的所有記憶體和驗證層。它可能會導致應用程序不穩定並且很難調試。此外,數據庫架構可能會在產品更新時發生變化。

我會推薦不同的解決方案:

  1. 如果您需要快速觸發器和來自觸發器的半實時作業,請使用服務代理隊列。在觸發器中,您將創建一條消息,然後使用 C# 服務、SSIS 或正常 Windows 服務來響應消息並創建作業。
  2. 如果觸發器可能較慢,並且您希望在作業創建失敗時使觸發器失敗,請從觸發器(C# 儲存過程或 OLE)呼叫 Web API。

作為旁注,DATEADD(HOUR, 4, GETDATE())不適用於冬季,您需要AT TIME ZONE在 SQL Server 中使用正確轉換為 UTC。

引用自:https://dba.stackexchange.com/questions/291903