tetthys/safejob
Composer 安装命令:
composer require tetthys/safejob
包简介
Financial-grade idempotent job framework with Laravel integration
README 文档
README
Tetthys SafeJob is a financial-grade job execution framework that guarantees
exactly-once success semantics even under retries, duplicate dispatches, or worker crashes.
It is designed for high-risk domains such as payments, wallets, settlements, and external side effects, and integrates naturally with Laravel 12 Queue while remaining framework-agnostic at the core.
Why SafeJob?
Laravel jobs are at-least-once by default.
This means:
- A job may run more than once
handle()may be re-executed after partial success- Side effects (payments, events, notifications) can be duplicated
SafeJob solves this by splitting execution into two strictly separated phases:
- Retry-safe work (can run many times)
- Exactly-once success effects (runs globally only once)
Execution Pipeline
Every SafeJob follows the same fixed pipeline:
┌────────────────────┐
│ tryLease() │ Acquire global execution right
│ (DB row + TTL) │
└─────────┬──────────┘
│
▼
┌────────────────────┐
│ perform() │ Retry-safe, idempotent work
│ (may run many) │
└─────────┬──────────┘
│
▼
┌────────────────────┐
│ finalizeSuccess() │ Atomically mark SUCCEEDED
│ (exactly once) │
└─────────┬──────────┘
│
▼
┌────────────────────┐
│ onSucceededOnce() │ Irreversible side effects
│ (exactly once) │
└────────────────────┘
If an exception occurs:
- If allowed by
FailurePolicy→ finalize as FAILED - Otherwise → exception is rethrown and normal Laravel retry applies
Installation
composer require tetthys/safejob php artisan migrate
This will:
- Register the Laravel service provider automatically
- Install the
safe_jobstable for lease & state tracking
Core Concepts
SafeJob (Business Logic)
You implement SafeJob, not Laravel Job logic.
use Tetthys\SafeJob\Core\Contracts\SafeJob; use Tetthys\SafeJob\Core\Contracts\Context; use Tetthys\SafeJob\Core\Contracts\IdempotencyKey; use Tetthys\SafeJob\Core\Value\Outcome; final class ChargeWalletSafeJob implements SafeJob { public function __construct( private string $chargeId ) {} public function key(): IdempotencyKey { return new IdempotencyKey('charge:' . $this->chargeId); } public function perform(Context $ctx): Outcome { // Retry-safe work only: // - idempotent DB writes // - upserts // - unique constraints return Outcome::ranSuccess(); } public function onSucceededOnce(Context $ctx): void { // Exactly-once side effects: // - emit domain event // - send notification // - publish message } }
Rules:
perform()must be safe to run multiple timesonSucceededOnce()must assume it runs only once globally
Laravel Job Integration
Your Laravel Job becomes a thin adapter.
use Illuminate\Contracts\Queue\ShouldQueue; use Tetthys\SafeJob\Integration\Laravel\Concerns\HandlesSafeJob; use Tetthys\SafeJob\Core\Contracts\SafeJob as SafeJobContract; final class ChargeWalletJob implements ShouldQueue { use HandlesSafeJob; public function __construct( public string $chargeId ) {} protected function safeJob(): SafeJobContract { return new ChargeWalletSafeJob($this->chargeId); } }
That is all.
- No manual locking
- No duplicate guards
- No custom retry logic
Failure Handling (Optional)
By default, no failure is finalized. All exceptions bubble up and Laravel retries normally.
You may define a FailurePolicy to explicitly finalize certain errors:
protected function failurePolicy(): FailurePolicy { return new class implements FailurePolicy { public function finalFailureFor(\Throwable $e): ?FinalFailure { if ($e instanceof BusinessRuleViolation) { return new FinalFailure( code: 'rule_violation', message: $e->getMessage() ); } return null; } }; }
Only when FinalFailure is returned will the job be permanently marked as FAILED.
Guarantees
SafeJob provides:
- ✅ Global exactly-once success
- ✅ Safe retries under crashes
- ✅ Duplicate dispatch protection
- ✅ Lease-based concurrency control
- ✅ Deterministic final state (SUCCEEDED / FAILED)
What it does not do:
- ❌ Distributed transactions
- ❌ Automatic idempotency inside your domain logic
When to Use
SafeJob is ideal for:
- Payments / Wallets / Escrow
- External API side effects
- Event publishing
- Financial or legal workflows
- Any job where “running twice” is unacceptable
Design Philosophy
Jobs must be retryable. Side effects must be final. The boundary must be explicit.
SafeJob enforces this boundary by design.
License
MIT
tetthys/safejob 适用场景与选型建议
tetthys/safejob 是一款 基于 PHP 开发的 Composer 扩展包,目前已累计 1 次下载、GitHub Stars 达 1, 最近一次更新时间为 2025 年 12 月 30 日, 在 PHP 生态内属于活跃度较高的组件。
我们在过去多个企业项目中使用过 tetthys/safejob 或与其功能相近的方案,如果你在选型或落地过程中遇到问题,例如 版本兼容、二次改造、私有化封装、与内部系统对接、生产 BUG 排查,欢迎联系我们协助评估。
基于 tetthys/safejob 在你已有业务上做功能扩展、字段裁剪、UI 适配、与内部账号 / 权限 / 日志系统的深度对接。
线上偶发问题、内存泄漏、慢查询、并发异常等排查修复;针对高流量场景做缓存、队列、索引层面的调优。
承接完整的项目从需求 → 设计 → 开发 → 上线 → 长期运维;也可按月提供技术保姆服务。
统计信息
- 总下载量: 1
- 月度下载量: 0
- 日度下载量: 0
- 收藏数: 1
- 点击次数: 17
- 依赖项目数: 0
- 推荐数: 0
其他信息
- 授权协议: MIT
- 更新时间: 2025-12-30