后台任务、检查点与发布回归:练习答案
参考实现
独立运行(包含完整最小状态机):
python
state = {"epoch":0, "status":"queued", "result":None}
def claim():
state["epoch"] += 1
state["status"] = "running"
return state["epoch"]
def commit(epoch, value):
if epoch != state["epoch"] or state["status"] != "running": return False
state.update(status="completed", result=value)
return True
x = claim()
state["status"] = "cancelled"
assert not commit(x,"late") and state["result"] is None
state["status"] = "queued"
y = claim()
assert y > x and commit(y,"ok")
print("cancel then restart")重启不是恢复旧 worker 的提交权;epoch 必须增加。
SQLite 取消后重启
将正文账本完整块保存为同目录 jobs.py,本答案另存 cancel_answer.py 运行。真正启动第二个进程,不能用同一个字典模拟重启。
python
import subprocess,sys
from tempfile import TemporaryDirectory
from pathlib import Path
import jobs
with TemporaryDirectory() as folder:
path=str(Path(folder)/'jobs.sqlite');db=jobs.database(path)
with db:db.execute("INSERT INTO jobs VALUES ('j1',0,0,'queued','')")
subprocess.run([sys.executable,jobs.__file__,path],check=True)
with db:db.execute("UPDATE jobs SET status='cancelled',epoch=epoch+1 WHERE id='j1'")
second=subprocess.run([sys.executable,jobs.__file__,path],capture_output=True,text=True)
assert second.returncode!=0 and 'terminal task' in second.stderr
assert db.execute("SELECT step,status,result FROM jobs WHERE id='j1'").fetchone()==(1,'cancelled','retrieved evidence')
db.close()
print('cancelled task remains at persisted step 1 after process restart')