跳轉到

排程作業(TsERP.SchedulerWorker)

TsERP 排程作業是一支獨立的 Windows Console 程式(TsERP.SchedulerWorker.exe),由 Windows 工作排程器每 5 分鐘觸發一次,負責行事曆事件 Email 通知AutoPilot 自動排程。本頁是給系統管理員 / DBA 看的部署與維運手冊。

功能簡介

舊版的 ERP 系統把這兩件工作放在 LogicBll.Timer.TimerBll 內的 DispatcherTimer只有當有人開著 ERP 主程式時才會跑。實務上這帶來幾個痛點:

  • 下班後沒人開 ERP,行事曆通知信不會寄出
  • AutoPilot 自動排程必須仰賴某個使用者「掛著」ERP
  • 多人同時開 ERP 時,每台都會跑同一份排程,造成重複通知

新版把排程邏輯抽成獨立 TsERP.SchedulerWorker.exe,部署到 server,由 Windows 工作排程器(schtasks)每 5 分鐘觸發一次。優點:

  • 不需要使用者開 ERP,server 上自動跑
  • 單一執行點,靠 Mutex 保證不重疊
  • 可獨立升級,與 ERP 主程式解耦
  • 失敗會留下 'F' 狀態 + log,方便管理員追查

與舊版 TimerBll 的差異

舊版 ERP 主程式仍保留 TimerBll 相關程式碼,但 MainWindowBtnTimerViewModel 已不再實際啟動該 timer(避免與本排程作業衝突)。請務必確認 server 上只有排程作業在跑,使用者端 ERP 不會重複觸發通知。

前置需求

項目 需求
作業系統 Windows Server 2019 / 2022(或 Windows 10 / 11 Pro)
.NET Runtime .NET 8 Desktop Runtime(x64)
SQL Server 可從排程主機連線到 ERP 各公司資料庫
Mailgun 可從排程主機對外發出 HTTPS request 到 Mailgun API
DatabaseList.xml 路徑 c:/TEMPS/SqlLocation/DatabaseList.xml,包含目標 DB 連線資訊
服務帳號 一個專用本機 / 網域帳號,能讀 XML、寫 log、連 SQL、連網

資料庫變更(DBA 必做)

排程作業靠兩支單一職責 SP 撈出待處理事件——dbo.TWORK_SKD_GET_PENDING_NOTIFY(待 Email 通知)與 dbo.TWORK_SKD_GET_PENDING_AUTOEXEC(待 AutoPilot 自動執行)。需要 DBA 先在每個目標公司資料庫做下列改動。

歷史對照

這兩支 SP 取代了原 TWORK_SKD_NOTIFYEVENT@QueryType=1 / =2 兩個分支),詳細決策見 ADR 0015。舊 SP 仍可保留 30 天再 drop。

1. 行事曆 base table 加欄位

行事曆事件的底層 table(即 Twork_skd_vw_eventitem view 對應的 base table)需要新增「執行開始時間」欄位,作為殭屍判定基準。

-- 範例 DDL,實際 table 名請依貴公司 schema 調整
ALTER TABLE [dbo].[行事曆事件 base table]
    ADD [執行開始時間] datetime NULL;
GO

欄位型別必須是 datetime

CalendarBll.Update已通知 / Update已完成 多載會把 DateTime.Now 透過 yyyy/MM/dd HH:mm:ss 格式字串傳給 SP,欄位型別必須能容納此值。

2. 建立兩支撈待辦事件 SP

完整 DDL 在 SqlBI/TWORK_SKD_GET_PENDING_NOTIFY.sqlSqlBI/TWORK_SKD_GET_PENDING_AUTOEXEC.sql,DBA 直接執行即可。摘要:

TWORK_SKD_GET_PENDING_NOTIFY(@datetime) — 待 Email 通知

CREATE PROCEDURE [dbo].[TWORK_SKD_GET_PENDING_NOTIFY]
    (@datetime datetime)
AS
BEGIN
    SET NOCOUNT ON;
    SELECT *
    FROM dbo.twork_vw_calendarevent
    WHERE 已審核 = 'Y'
      AND 是否停用 <> 'Y'
      AND 通知 = 'Y'
      AND 通知帳號 <> ''
      AND 已通知 <> 'Y'
      AND @datetime >= 通知時間;
END

TWORK_SKD_GET_PENDING_AUTOEXEC(@datetime) — 待 AutoPilot 自動執行

CREATE PROCEDURE [dbo].[TWORK_SKD_GET_PENDING_AUTOEXEC]
    (@datetime datetime)
AS
BEGIN
    SET NOCOUNT ON;
    SELECT TOP 20 *
    FROM twork_vw_calendarevent
    WHERE 已完成 NOT IN ('Y', 'F')
      AND (已完成 <> 'R' OR 執行開始時間 < DATEADD(MINUTE, -10, @datetime))
      AND 已審核 = 'Y'
      AND 是否停用 <> 'Y'
      AND 是否自動執行 = 'Y'
    ORDER BY 預定時間 ASC;
END

關鍵點:

  • TOP 20 對應 Scheduler.BatchSize,每次最多 20 筆
  • ORDER BY 預定時間 ASC 依時間先進先出
  • 已完成 NOT IN ('Y','F'):已完成的 Y 與失敗的 F 都不再撈
  • 殭屍回收條件 (已完成 <> 'R' OR 執行開始時間 < DATEADD(MINUTE, -10, @datetime)):非執行中(不是 R),或雖是 R 但 10 分鐘前就開始 → 視為前一輪 crash 重撈
  • @datetime 是殭屍判定基準時間,由 caller 傳當下時間,便於外部測試

3. 新增 SP dbo.TWORK_SKD_UPDATE_EVENT_STATUS

CalendarBll.Update已通知(pkid, status, time)Update已完成(pkid, status, time) 多載會呼叫這支 SP 一次更新「狀態 + 執行開始時間」。請建立:

參數 對應 C# 端 說明
LP_P1 type '1'=已通知、'2'=已完成
LP_P2 pkid 事件主鍵
LP_P3 status 'R'=執行中(Running) / 'Y'=完成 / 'F'=失敗 / ''=重設
LP_P4 timestamp yyyy/MM/dd HH:mm:ss 字串;空字串代表不更新時間

LP_P1='2'(已完成分支)且 LP_P3='Y' 時,SP 會自動把 [完成時間] 設為 GETDATE();其他狀態(R/F/'')不動 完成時間

CREATE PROCEDURE [dbo].[TWORK_SKD_UPDATE_EVENT_STATUS]
    @LP_P1 varchar(1),    -- 1 = 已通知, 2 = 已完成
    @LP_P2 varchar(50),   -- pkid
    @LP_P3 varchar(1),    -- 'R' / 'Y' / 'F' / ''
    @LP_P4 varchar(20)    -- yyyy/MM/dd HH:mm:ss 或 ''
AS
BEGIN
    SET NOCOUNT ON;

    DECLARE @StartTime datetime = NULL;
    IF @LP_P4 <> ''
        SET @StartTime = CONVERT(datetime, @LP_P4, 111);

    IF @LP_P1 = '1'
        UPDATE [行事曆事件 base table]
           SET [已通知] = @LP_P3,
               [執行開始時間] = CASE WHEN @LP_P4 = '' THEN [執行開始時間] ELSE @StartTime END
         WHERE [pkid] = @LP_P2;
    ELSE IF @LP_P1 = '2'
        UPDATE [行事曆事件 base table]
           SET [已完成] = @LP_P3,
               [執行開始時間] = CASE WHEN @LP_P4 = '' THEN [執行開始時間] ELSE @StartTime END,
               [完成時間] = CASE WHEN @LP_P3 = 'Y' THEN GETDATE() ELSE [完成時間] END,
               [是否停用] = CASE WHEN @LP_P3 = 'Y' THEN 'Y' ELSE '' END
         WHERE [pkid] = @LP_P2;
END
GO

SP 名稱

請依貴公司命名慣例調整 TWORK_SKD_UPDATE_EVENT_STATUS。Common 端是用 Procedure.TWORK_SKD_UPDATE_EVENT_STATUS.Name 取的常數,DBA 改完 SP 後若名稱有異,請同步通知開發端調整 Procedure 列舉。

部署步驟

1. 發佈 Console 程式

在開發機把 TsERP.SchedulerWorker 專案 publish 為 framework-dependent:

dotnet publish TsERP.SchedulerWorker/TsERP.SchedulerWorker.csproj `
    -c Release `
    -r win-x64 `
    --self-contained false `
    -o C:\Publish\Scheduler

或 self-contained(檔案大但不需在 server 裝 .NET):

dotnet publish TsERP.SchedulerWorker/TsERP.SchedulerWorker.csproj `
    -c Release `
    -r win-x64 `
    --self-contained true `
    -o C:\Publish\Scheduler

2. 複製到 server

C:\Publish\Scheduler\ 整個資料夾複製到 server,建議放:

C:\ERPDeploy\Scheduler\
├── TsERP.SchedulerWorker.exe
├── TsERP.SchedulerWorker.dll
├── appsettings.json
└── ...其他依賴 dll...

3. 建立 log 目錄

排程作業透過 SchedulerLog 把所有歷程(INFO 與 ERROR)寫到 C:\temps\scheduler\yyyy-MM-dd.txt,每天一個檔。首次執行時若資料夾不存在會自動建立,但建議事先建好並設好權限:

New-Item -Path "C:\temps\scheduler" -ItemType Directory -Force
icacls "C:\temps\scheduler" /grant "<服務帳號>:(OI)(CI)M"

指令說明

New-Item

參數 意思
-Path "C:\temps\scheduler" 建在這個路徑
-ItemType Directory 建的是資料夾(不是檔案)
-Force 父資料夾 C:\temps\ 不存在時自動建出來;目標已存在時不報錯

icacls:Windows 內建的 ACL(檔案權限)編輯工具。

參數 意思
/grant 授予權限(不是拒絕、不是取代既有權限)
<服務帳號> 佔位符,替換成實際帳號(見下方範例)
(OI) Object Inherit — 套用到資料夾內所有檔案
(CI) Container Inherit — 套用到所有子資料夾
M Modify — 可讀 / 可寫 / 可刪檔,不能改權限或拿走所有權

服務帳號範例

依你工作排程器的「執行此工作時,請使用下列使用者帳戶」設定替換 <服務帳號>

# 本機專屬服務帳號(手冊推薦做法)
icacls "C:\temps\scheduler" /grant "tsERPSched:(OI)(CI)M"

# 用 SYSTEM 帳號跑
icacls "C:\temps\scheduler" /grant "SYSTEM:(OI)(CI)M"

# 網域帳號(公司網域 DARBWARE,使用者 erpsvc)
icacls "C:\temps\scheduler" /grant "DARBWARE\erpsvc:(OI)(CI)M"

不知道目前用哪個帳號?開「工作排程器」 → 找到 TsERP Scheduler → 點選 → 看下方「一般」分頁的「執行此工作時,請使用下列使用者帳戶」欄位。

驗證

icacls "C:\temps\scheduler"

輸出應包含類似 tsERPSched:(OI)(CI)(M) 的行,代表已套用成功。

什麼情況可以省略 icacls

若排程是用 Administrator 或具有同等權限的帳號跑(例如個人開發機自己當管理員),對 C:\temps\ 預設就有完整權限,第二條可跳過。正式環境若用低權限服務帳號則必設 — 不設會導致 SchedulerLog 寫檔失敗(但因為 try/catch 吞例外,會靜默失敗,磁碟上完全看不到 log 檔)。

4. 確認 DatabaseList.xml

排程作業共用 ERP 主程式的 SQL 連線設定,會讀取:

c:/TEMPS/SqlLocation/DatabaseList.xml

請確認此檔案於 server 存在,且含有 appsettings.jsonScheduler.Databases[*].Name 對應的 <DataBase> 條目。

5. 編輯 appsettings.json

打開 C:\ERPDeploy\Scheduler\appsettings.json,依環境調整(詳見配置檔說明)。

6. 手動跑一次驗證

以服務帳號身份開啟 PowerShell:

cd C:\ERPDeploy\Scheduler
.\TsERP.SchedulerWorker.exe

預期 console 輸出:

[SchedulerJob] === DB darbcylog1 on TWORKSQL ===
[SchedulerJob] Notify: no rows.
[SchedulerJob] AutoPilot: no rows.
[Scheduler] Done. exitCode=0

如果出現 Fatal error 或 exitCode 為 2,請先處理疑難排解再進入下一步。

服務帳號設定

建議不要Administrator 或一般使用者帳號跑排程作業,請建立專屬本機帳號:

1. 建立本機帳號

$pw = Read-Host -AsSecureString "Set password"
New-LocalUser -Name "tsERPSched" -Password $pw -PasswordNeverExpires -UserMayNotChangePassword

或在「電腦管理 → 本機使用者及群組 → 使用者」手動新增。

2. 賦予最小權限

權限 設定方式
以批次工作登入 (SeBatchLogonRight) 本機安全性原則 → 使用者權限指派 → 「以批次工作登入」加入 tsERPSched
讀取 c:\TEMPS\SqlLocation\DatabaseList.xml 在檔案內容 → 安全性 → 加入 tsERPSched 給「讀取」
修改 C:\ERPDeploy\Scheduler\ 同上,給「修改」
修改 C:\temps\scheduler\ SchedulerLog 寫入路徑(每日一檔)
SQL Server 連線 在 SQL Server 加入 Login,授予 ERP 各公司資料庫對應 SP 的 EXECUTE 權限
網路 確認防火牆允許對 api.mailgun.net HTTPS(443)出站連線

無互動登入即可

服務帳號不需要「允許本機登入」權限,建議於本機安全性原則「拒絕從本機登入」加入此帳號,降低被當作互動帳號濫用的風險。

Windows 工作排程器設定

1. 建立排程

開啟「工作排程器」 → 「建立工作」(不是簡單建立工作):

一般

  • 名稱TsERP Scheduler
  • 使用者帳戶tsERPSched
  • 不論使用者是否登入皆執行:勾
  • 以最高權限執行:依需求(通常不需勾)
  • 設定:Windows Server 2019 / 2022 / 11

觸發程序

  • 新增觸發程序,每日
  • 開始:選擇生效日,時間 00:00:00
  • 重複工作每:5 分鐘
  • 持續時間:無限期
  • 已啟用:勾

動作

  • 動作:啟動程式
  • 程式或指令碼:C:\ERPDeploy\Scheduler\TsERP.SchedulerWorker.exe
  • 開始於(選擇性):C:\ERPDeploy\Scheduler\

條件

  • 只有在電腦使用 AC 電源時才啟動工作:取消勾選(server 不需要)
  • 只有在下列網路連線可用時才啟動:依環境

設定

選項 建議值
允許隨選執行此工作
如果排定的開始時間錯過則盡快執行此工作
如果工作失敗,每隔重新啟動 不勾(讓下一個 5 分鐘自然觸發即可)
停止超過下列時間的工作 勾,4 分鐘(hard timeout,防止某次 hang 卡住下次觸發)
如果執行中的工作未在要求時結束,將強制停止
如果工作未排定再次執行則在以下時間之後刪除 不勾
如果工作已在執行則使用下列規則 不要啟動新的執行個體

務必設「不要啟動新的執行個體」

雖然程式內部已有 Mutex 保護,但工作排程器層級也要設成「不重疊」,避免同時噴出多個 process 競爭 log 檔案 handle。

2. 用 schtasks CLI 建立(替代方式)

schtasks /Create ^
    /TN "TsERP Scheduler" ^
    /TR "C:\ERPDeploy\Scheduler\TsERP.SchedulerWorker.exe" ^
    /SC MINUTE /MO 5 ^
    /RU "tsERPSched" /RP "***" ^
    /RL LIMITED ^
    /F

CLI 設定完仍建議在 GUI 確認「設定」分頁的「不要啟動新的執行個體」與「4 分鐘 timeout」是否正確。

配置檔說明

appsettings.json 結構:

{
  "MailGun": {
    "ApiKey": "<your-mailgun-api-key>",
    "Domain": "mg.darbware.com",
    "Sender": "@\"TWork ERP Mail Service <tworkservice@mg.darbware.com>\""
  },
  "Scheduler": {
    "Databases": [
      { "Name": "darbzdcsa1", "ConnectionString": "" }
    ],
    "AlertRecipients": ["admin@example.com"],
    "ZombieTimeoutMinutes": 10,
    "BatchSize": 20,
    "DefaultSrvdbid": 1
  }
}

MailGun 區段

欄位 說明
ApiKey Mailgun API Key(私鑰,請勿外流)
Domain Mailgun 域名
Sender 寄件人字串,含格式化引號

Scheduler 區段

欄位 必填 預設 說明
Databases [] 要處理的公司資料庫清單,留空陣列代表跑 DatabaseList.xml 內全部 DBName 對應 XML 內 <DataBase> 名稱,須完全一致(不分大小寫)
Databases[*].ConnectionString "" 預留欄位;目前實際連線仍以 DatabaseList.xml 為準,這裡填了不會生效
AlertRecipients [] 致命錯誤時的告警收件人(保留欄位,目前由 SchedulerLog 處理;未來可擴充用)
ZombieTimeoutMinutes 10 殭屍回收門檻(分鐘)。注意:實際判定寫死在 SP 內的 DATEADD(MINUTE, -10, ...),此欄位目前是給 SP 端參考的契約值,調動時請同步改 SP
BatchSize 20 每次最多處理筆數。注意:實際 TOP 20 寫死在 SP 內,調動時請同步改 SP
DefaultSrvdbid 1 SchedulerUser.Srvdbid 預設值,影響 LoggingId / log 路由

ZombieTimeoutMinutes / BatchSize 是契約值

這兩個欄位目前不會主動傳到 SQL 端,SP 內的 TOP 20DATEADD(MINUTE, -10) 是寫死的。把它放在 config 是為了讓管理員一眼看到「殭屍 = 10 分鐘」「批次 = 20 筆」這兩個約定,真正要改值請改 SP

多公司支援

跑單一公司

"Databases": [
  { "Name": "darbcylog1" }
]

跑多公司(依序,同一 process 內逐個切 connection)

"Databases": [
  { "Name": "darbcylog1" },
  { "Name": "darbzdcsa1" },
  { "Name": "darbtest" }
]

排程作業會依序處理每個 DB(呼叫 IDatabaseConnection.ChangeParameter),每個 DB 各自跑一輪 Notify + AutoPilot。某個 DB 失敗不影響其他 DB。

跑全部 DB

"Databases": []

留空陣列時,排程作業會把 DatabaseList.xml 內的所有 DB 都掃過一遍。

多公司 + 4 分鐘 timeout 的取捨

如果有 5 個以上公司、每家都有大量待處理事件,5 分鐘觸發 + 4 分鐘 hard timeout 可能不夠。建議:

  • 拆成多支排程作業(複製目錄、各自 appsettings.json 跑不同 DB)
  • 或調高 BatchSize 並把 timeout 拉到 8 分鐘,但觸發改成每 10 分鐘

失敗處理 / 重設 'F' 狀態

'F' 狀態怎麼來

MailGun 寄信失敗、AutoPilot 動作 throw exception、或回傳 IsSuccess = false 時,排程作業會把該事件的 已通知已完成 標為 'F',並在 log 留下原因。

'F' 狀態不會被自動重撈(SP 過濾 NOT IN ('Y', 'F')),需要管理員手動處理。

重設讓事件再跑一次

在 SQL Management Studio 執行:

-- 把單一事件重新放回待處理
UPDATE [行事曆事件 base table]
   SET [已通知] = '',          -- 或 'N',依貴司 default
       [執行開始時間] = NULL
 WHERE [pkid] = '<目標 pkid>';

-- AutoPilot 同理
UPDATE [行事曆事件 base table]
   SET [已完成] = '',
       [執行開始時間] = NULL
 WHERE [pkid] = '<目標 pkid>';

批次重設今天所有失敗事件

UPDATE [行事曆事件 base table]
   SET [已通知] = '',
       [執行開始時間] = NULL
 WHERE [已通知] = 'F'
   AND CAST([預定時間] AS date) = CAST(GETDATE() AS date);

先確認失敗原因

重設前請先看 log(C:\temps\scheduler\yyyy-MM-dd.txt)確認失敗原因。如果是 Mailgun 帳號爆量、收件人 email 格式錯誤,重設只會再失敗一次。先修根因再重設。

殭屍 'X' 狀態

什麼是殭屍

排程作業在處理一筆事件時,會先把狀態標為 'X'(執行中)並寫入 執行開始時間 = DateTime.Now。正常情況下幾秒內就會更新成 'Y'(成功)或 'F'(失敗)。

但如果 process 在這當中被強制終止(OOM、Windows 關機、被 timeout 殺掉、藍屏),事件會卡在 'X' 永遠不會被更新 → 殭屍

自動回收

SP 的查詢條件包含:

[已完成] <> 'X' OR [執行開始時間] < DATEADD(MINUTE, -10, GETDATE())

意思是:'X' 狀態超過 10 分鐘的事件會被當成殭屍重新撈出。下次觸發排程作業時,這些殭屍會被重跑。

手動處理

若要立刻把殭屍復活(不等 10 分鐘):

UPDATE [行事曆事件 base table]
   SET [已通知] = '',
       [執行開始時間] = NULL
 WHERE [已通知] = 'X';

為什麼是 10 分鐘

排程是 5 分鐘觸發 + 4 分鐘 timeout,正常一次跑滿不會超過 4 分鐘。10 分鐘給予 1 個完整週期的緩衝,避免「上一輪還沒跑完」就被當殭屍。

疑難排解 (FAQ)

信沒寄出去怎麼辦?

依序檢查:

  1. 手動跑一次TsERP.SchedulerWorker.exe),看 console 輸出。如果出現 Notify pkid=... -> F (...),看括號內錯誤訊息
  2. 看 logC:\temps\scheduler\yyyy-MM-dd.txt,找最近的 [ERROR] [SchedulerJob] Notify pkid=... -> F (...)
  3. 確認 Mailgun:API Key 是否過期、Domain 是否被停用、額度是否爆
  4. 確認收件人:行事曆事件的 通知帳號 欄位是否有效 email
  5. 確認 SP:手動 EXEC dbo.TWORK_SKD_GET_PENDING_NOTIFY @datetime = GETDATE() 看有沒有撈到 row。若沒有,問題在 SP 的過濾條件
AutoPilot 沒跑怎麼辦?
  1. 確認該事件的 通知方式 不是 Email(AutoPilot 走的是 LP_P1='2' 流程,跟通知信不同)
  2. 看 log 是否有 AutoPilot pkid=... -> F
  3. 確認 IAutoPilotHelper.ExecuteMethod 對該事件回傳的 Message
  4. AutoPilot 動作本身可能依賴主程式的某些 plugin / DLL,請確認 TsERP.SchedulerWorker 部署目錄含有對應 DLL
log 看哪裡?
  • SchedulerLog(主要 log)C:\temps\scheduler\yyyy-MM-dd.txt,每天一個檔,含完整 INFO + ERROR 歷程
  • stdout / stderr:手動執行 .exe 時可在 console 看到;工作排程器啟動時 stdout 會被丟棄(已不需要靠 stdout 看歷程,SchedulerLog 已涵蓋)
  • Mailgun 端Mailgun Logs
  • 行格式yyyy-MM-dd HH:mm:ss [LEVEL] 訊息,例:2026-05-05 02:30:00 [INFO] [SchedulerJob] === DB darbnogilog1 on localhost\t2022bin ===
exit code 1 跟 2 有什麼差別?
exit code 含義 處理方式
0 全部成功(含「沒有資料要處理」) 無需處理
1 部分失敗:某個 DB 的 NotifyAsync 或 AutoPilotAsync 拋例外,但其他 DB 仍跑完 看 log 找哪個 DB 失敗,多半是 SP 沒改、權限不足、SQL 連線問題
2 致命錯誤:根本沒進入主流程(DI 註冊失敗、appsettings 解析失敗、Mutex 競爭以外的問題) 看 stderr 第一行 Fatal error: ...,通常是設定檔錯誤或缺 DLL
排程作業會跟正在開 ERP 的使用者衝突嗎?

不會。新版 ERP 主程式的 MainWindowBtnTimerViewModel移除 TimerBll 欄位,使用者端不會再啟動本機 timer。所有通知/AutoPilot 都由 server 上的排程作業統一處理,避免重複。

舊版 client 升級前的過渡期

若 server 已啟用排程作業、但部分使用者還在用舊版 ERP client(仍含 TimerBll 啟動邏輯),會出現重複通知。請務必同步升級所有 client,或暫時停用 server 排程作業。

前一次還沒跑完,下一次又被觸發了,怎麼辦?

程式內以 Global\TsERP_Scheduler Mutex 保護單一執行;後到的 process 會印 Another scheduler instance is running. Exiting. 後 exit code 0 結束。工作排程器層級也設了「不要啟動新的執行個體」雙保險。

若想驗證,可手動連續執行兩次 TsERP.SchedulerWorker.exe,第二次應立即結束。

排程作業要怎麼停?

工作排程器 → 找到 TsERP Scheduler停用。已在執行中的 process 會跑完當下這輪,不會被中斷(除非超過 hard timeout)。

若要立即終止 process:在工作管理員 kill TsERP.SchedulerWorker.exe。下次觸發前殭屍 'X' 狀態會自動回收。

可以調整觸發間隔嗎?

可以。修改工作排程器觸發程序的「重複工作每 5 分鐘」為其他值即可。但請注意:

  • 間隔太短(< 2 分鐘)會頻繁敲 SQL,影響效能
  • 間隔太長(> 30 分鐘)通知信延遲體感很差
  • 改間隔後請同步調整 hard timeout(建議 = 觸發間隔 - 1 分鐘)與 SP 的殭屍判定門檻(建議 = 觸發間隔 × 2)

截圖補充清單

以下截圖建議補上,可放於 docs/admin/images/

  • [需補:scheduler-task-general.png] — 工作排程器「一般」分頁完成設定畫面
  • [需補:scheduler-task-trigger.png] — 工作排程器「觸發程序」分頁,5 分鐘重複設定畫面
  • [需補:scheduler-task-action.png] — 工作排程器「動作」分頁,指向 exe 的設定畫面
  • [需補:scheduler-task-settings.png] — 工作排程器「設定」分頁,4 分鐘 timeout 與「不要啟動新的執行個體」畫面
  • [需補:scheduler-console-output.png] — 手動執行 exe 的 console 成功輸出畫面
  • [需補:scheduler-log-folder.png]C:\temps\scheduler\ 內的 log 範例

相關功能

  • L 聯絡傳訊:行事曆通知對應的 Email 寄送設定
  • A 系統管理:使用者帳號與權限(排程作業使用 SchedulerUser 假身份)