如何通过SQL写入Hangfire数据库表直接触发作业
直接写库触发Hangfire作业实操方案
直接操作Hangfire数据库触发作业是可行的,但你之前判断只需要操作Hash、Set两张表是不对的,缺了核心队列表、作业表、状态表的写入会导致作业永远无法被调度,甚至搞乱整个Hangfire的状态数据,按下面的步骤操作即可。
前置准备
- 操作前对Hangfire相关业务库做一次全量备份,避免误写数据导致服务异常
- 提前从历史同类型作业记录里提取完整的调用参数:包括作业方法的全限定类名、方法名、入参序列化值、所属队列名(默认是
default)。不要自己手动构造序列化参数,Hangfire有固定的序列化规则,自己拼的参数大概率会导致作业执行时抛出类型不匹配错误,直接复用历史成功作业的对应字段值改业务参数就行 - 所有写入操作必须放在同一个数据库事务里提交,避免产生脏数据
- 所有时间字段统一使用UTC时间,禁止用本地时间,否则会出现调度时间错乱
操作步骤
方式一:触发已有周期作业(Recurring Job,最推荐,出错概率最低)
如果你要触发的是已经在Hangfire里配置好的周期作业,不用新建作业记录,操作两步就行:
- 找到Hash表中Key为
recurring-job:{你的周期作业名}的记录,把NextExecution字段的值改成一个早于当前UTC时间的时间值(格式和同表现有记录保持一致) - 往Set表插入一条记录:
- Key:固定为
recurring-jobs:trigger - Score:填当前UTC时间对应的Unix时间戳(格式和同表现有记录一致)
- Value:填你的周期作业名
提交事务后等最多15秒(Hangfire周期调度器默认扫描间隔),就会自动生成对应的排队作业,不需要操作其他表。
- Key:固定为
方式二:手动新建一次性作业触发
如果是临时触发没有配置周期的作业,按下面顺序写表:
- 插入Job表主记录
Job表是作业主表,直接插入一条新记录,自增主键返回的Id就是新作业的全局ID,字段填法:InvocationData:复用历史同类型作业的对应字段,对应作业的类、方法标识Arguments:作业入参的序列化值,优先复用历史同参数作业的值CreatedAt:当前UTC时间StateName:固定填EnqueuedExpireAt:可填NULL,或按现有作业的过期规则填N天后的时间StateId:先留空,后续插入状态表后回写
- 插入State表状态记录
State表存作业的状态流转历史,插入一条新记录:JobId:上一步拿到的新作业IdName:固定填EnqueuedReason:填Manually triggered via DB即可CreatedAt:当前UTC时间Data:状态元数据的JSON串,直接抄现有Enqueued状态作业的Data字段,修改里面的EnqueuedAt时间为当前UTC时间即可
插入后拿到自增的StateId,回写到第一步Job表记录的StateId字段。
- 写入Hash表状态元数据
插入3条Hash记录,Key统一为job:{新作业Id}:state:- Field为
EnqueuedAt,Value为当前UTC时间的序列化字符串,格式和现有排队作业一致 - Field为
Queue,Value为作业所属队列名,默认是default - Field为
Reason,Value为Manually triggered via DB
- Field为
- 写入Set表索引记录
插入2条Set记录:- 第一条:Key为
queue:{队列名}(默认是queue:default),Score为当前UTC时间对应的Unix时间戳,Value为新作业Id的字符串形式 - 第二条:Key为
jobs:enqueued,Score和第一条保持一致,Value为新作业Id的字符串形式
- 第一条:Key为
- 写入JobQueue表(核心,漏写就不会被调度)
这张表是Hangfire工作线程拉取待执行作业的核心队列,必须插入一条记录:JobId:新作业IdQueue:作业所属队列名FetchedAt:填NULLFetchToken:填NULL
- 写入Counter表(可选,仅用于Dashboard统计)
插入一条统计记录,不写不影响作业执行,只是Dashboard的排队计数会不准:Key:stats:enqueuedValue:1ExpireAt:填当前时间加15分钟即可,该计数是临时值,会自动过期清理
排错说明
提交事务后如果1分钟内Dashboard没看到作业进入排队队列,按顺序检查:
- Job表中对应Id的记录
StateName是不是Enqueued - JobQueue表有没有对应JobId的记录,
FetchedAt是不是为NULL - Set表
queue:{队列名}的集合里有没有对应的JobId值 - 所有时间字段是不是用的UTC时间格式
附参考表结构样例:

内容的提问来源于stack exchange,提问作者Poseidon
相关产品推荐
相关产品推荐

