رفتن به متن راهنما
همه‌ی راهنماها

راهکار جایگزین (Fallback)

برای یک عملیات مقدار جایگزین تعیین کنید تا هنگام شکست فراخوانی برگردد. مشخص کنید رد شدن‌ها هم جایگزین شوند یا نه، و بدانید چه چیزی هرگز جایگزین نمی‌شود.

برنامه Reqtide PHP 0.1.0آخرین بررسی زمان خواندن 4 دقیقه

در این صفحه

بلوک‌های کد این صفحه از examples/09-choosing-policies.php (opens in a new tab) گرفته شده‌اند. اسکریپت طولانی‌تر و توضیح‌دار در examples/04-fallback.php (opens in a new tab) است.

راهکار جایگزین به یک عملیات تعلق دارد

راهکار جایگزین (Fallback) همان FallbackOperation است که به یک عملیات وصل می‌کنید. آن را با آرگومان fallback: به newContext() می‌دهید. این شیء Outcome اصلی را می‌گیرد و مقدار جایگزین را برمی‌گرداند. اگر context یک پایپ‌لاین هیچ fallback نداشته باشد، آن پایپ‌لاین هیچ نتیجه‌ای را عوض نمی‌کند.

PHP
/** @implements FallbackOperation<string> */
final class CachedCatalog implements FallbackOperation
{
    public function invoke(Outcome $original, ExecutionContext $context): string
    {
        return 'cached catalog';
    }
}

برای اینکه fallback جای یک شکست را بگیرد، دو شرط باید برقرار باشد: عملیات یک fallback داشته باشد و طبقه‌بند (classifier) شما با ExceptionClassifier::fallbackOn() آن استثنا را مجاز اعلام کرده باشد. پیش‌فرض هیچ استثنایی نیست. هر استثنایی را که فهرست نکرده باشید، Reqtide بدون تغییر برمی‌گرداند.

مشخص کنید چه چیزی جایگزین شود

به‌طور پیش‌فرض fallback فقط نتیجهٔ کار خود callable شما را جایگزین می‌کند. با FallbackScope::IncludeAdmissionRefusals می‌تواند رد شدن توسط مدارشکن، سقف اجرای هم‌زمان (Bulkhead)، محدودیت نرخ یا دورهٔ انتظار را هم جایگزین کند.

همهٔ پایپ‌لاین‌های این راهنما از همین دو گزینهٔ الزامی شروع می‌شوند:

PHP
$base = static fn(): PipelineBuilder => PipelineBuilder::profile('choosing', 'v1')
    ->partition('shop', 'prod', 'catalog-api')
    ->attemptTimeout(Duration::seconds(2), AttemptTimeoutRequirement::Cooperative);

$ok = static fn(): string => 'ok';
$context = static fn(CompiledPipeline $pipeline): ExecutionContext => $pipeline->newContext(Duration::seconds(30));

این قطعه کد تنها توکن محدودیت نرخ را مصرف می‌کند. بعد برای هر یک از دو دامنه فراخوانی دومی انجام می‌دهد:

PHP
echo "-- 5. Fallback: replace failures, and optionally refusals\n";
$build = static fn(FallbackScope $scope): CompiledPipeline => $base()
    ->rateLimit(PipelineBuilder::tokenBucket(1, 1, Duration::seconds(3600)))
    ->fallbackScope($scope)
    ->compileInMemory(ExceptionClassifier::create()->fallbackOn(\Throwable::class));
foreach ([FallbackScope::BusinessOutcomesOnly, FallbackScope::IncludeAdmissionRefusals] as $scope) {
    $pipeline = $build($scope);
    $pipeline->execute($ok, $pipeline->newContext(Duration::seconds(30))); // uses the only token
    try {
        $value = $pipeline->execute($ok, $pipeline->newContext(Duration::seconds(30), fallback: new CachedCatalog()));
        echo "{$scope->value}: second call returned '{$value}'\n";
    } catch (AdmissionRejectedException | AdmissionDeferredException $e) {
        echo "{$scope->value}: second call refused with {$e->reason()->value}\n";
    }
}
Text
-- 5. Fallback: replace failures, and optionally refusals
business_outcomes_only: second call refused with rate.exhausted
include_admission_refusals: second call returned 'cached catalog'

دامنهٔ پیش‌فرض رد شدن را به دست شما می‌رساند، پس می‌دانید که محدود شده‌اید. با IncludeAdmissionRefusals فراخوانی دوم مقدار کش‌شده را برمی‌گرداند. رد شدن از بین نمی‌رود: حالت تفصیلی آن را در policyCause نگه می‌دارد. جایگزینی که رد شدن‌ها را پنهان کند، محدود شدن را هم پنهان می‌کند. پس این دامنه را آگاهانه انتخاب کنید.

تنظیم fallbackScope(IncludeAdmissionRefusals) دست‌کم یک سیاست پذیرش لازم دارد: محدودیت نرخ، مدارشکن، سقف هم‌زمانی یا دورهٔ انتظار. در غیر این صورت builder این ترکیب را رد می‌کند.

آنچه fallback هرگز جایگزین نمی‌کند

  • مهلت کل. اگر مهلت کل تمام شده باشد، نتیجه deadline_exceeded است.
  • لغو. این در حین اجرای fallback هم برقرار است. اگر در حین اجرای fallback لغو درخواست شود، نتیجه cancelled می‌شود و حالت تفصیلی هنوز مقدار یا استثنایی را که fallback تولید کرده نگه می‌دارد. مهلتی که در حین اجرای fallback تمام شود، بر لغو مقدم است.
  • شکست زیرساخت، مثلاً در دسترس نبودن backend حالت. وقتی حالت خود Reqtide در دسترس نیست، رفتاری از خودش نمی‌سازد.

راهکار جایگزین مهلت کل عملیات را با تلاش‌های قبلی تقسیم می‌کند و در همان بودجهٔ زمانی اجرا می‌شود.

وقتی خود fallback شکست می‌خورد

اگر fallback استثنا پرتاب کند، در حالت ساده با FallbackFailedException گزارش می‌شود و استثنای خود fallback با getPrevious() در دسترس است. در حالت تفصیلی وضعیت نهایی fallback_failed است. شکست اصلی روی استثنا باقی می‌ماند. هر دو مورد در اسکریپت توضیح‌دار 04-fallback.php دیده می‌شود.

آزمون fallback

تلاش‌های ناموفق را از پیش تعیین کنید، سپس تعداد ارسال‌ها و رویدادهای ثبت‌شده را بررسی کنید. روش کار در آزمون با ساعت مجازی آمده است.