定制 tetthys/safejob 二次开发

按需修改功能、优化性能、对接业务系统,提供一站式技术支持

邮箱:yvsm@zunyunkeji.com | QQ:316430983 | 微信:yvsm316

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:

  1. Retry-safe work (can run many times)
  2. 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_jobs table 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 times
  • onSucceededOnce() 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 我们能提供哪些服务?
定制开发 / 二次开发

基于 tetthys/safejob 在你已有业务上做功能扩展、字段裁剪、UI 适配、与内部账号 / 权限 / 日志系统的深度对接。

BUG 修复 & 性能优化

线上偶发问题、内存泄漏、慢查询、并发异常等排查修复;针对高流量场景做缓存、队列、索引层面的调优。

项目外包 & 长期维护

承接完整的项目从需求 → 设计 → 开发 → 上线 → 长期运维;也可按月提供技术保姆服务。

yvsm@zunyunkeji.com QQ:316430983 微信:yvsm316 西安尊云信息科技 · 专注 PHP / Go / 分布式系统研发

统计信息

  • 总下载量: 1
  • 月度下载量: 0
  • 日度下载量: 0
  • 收藏数: 1
  • 点击次数: 17
  • 依赖项目数: 0
  • 推荐数: 0

GitHub 信息

  • Stars: 1
  • Watchers: 0
  • Forks: 0
  • 开发语言: PHP

其他信息

  • 授权协议: MIT
  • 更新时间: 2025-12-30