leyton/laravel-circuit-breaker

Laravel 实现断路器模式

1.0 2024-05-17 08:58 UTC

This package is auto-updated.

Last update: 2024-09-09 14:55:37 UTC


README

断路器模式对于确保软件的健壮性至关重要。它阻止故障扩散,即使在服务遇到问题时也能保持操作稳定性。通过提供视觉反馈和改进用户体验,它使应用程序运行顺畅。此外,它简化了维护和故障排除,使问题解决更快。总的来说,集成断路器模式对于提高可靠性和用户满意度至关重要。

Circuit Breaker states

您可以在以下链接中找到更多关于此模式的详细信息 断路器模式

安装

composer require leyton/laravel-circuit-breaker

安装后,请确保发布资源

php artisan vendor:publish --provider="Leyton\LaravelCircuitBreaker\LaravelCircuitBreakerServiceProvider"

您将在 config/circuit-breaker.php 文件中找到所有需要的配置。

<?php

return [
  'threshold' => 10, // number of trials to pass from half-open to closed/open and from closed to half-open
  'available_after_seconds' => 10, // the seconds it takes while in the open status
  'driver' => 'redis', // the cache store driver
];

使用

该包为您提供了一个简单的 API 来使用。

<?php

use Leyton\LaravelCircuitBreaker\Circuit;
use Leyton\LaravelCircuitBreaker\Exceptions\RequestFailedException;


function goToGoogle(){
  try{
    $response = Http::get("https://gooogle.com");

    if($response->status() === 500){
        throw new RequestFailedException();
    }

  return "all is good";
  }catch(\Exception $exception){
    throw new RequestFailedException();
  }
}

// The Circuit is resolved out of the service container

$circuit = app()->make(Circuit::class);

//The run method expects the service name and the function that wraps the service
//It should throw the RequestFailedException when the service is not responding as expected
$packet =  $circuit->run("go-to-google", fn() => goToGoogle());

包对象持有回调的结果和服务的状态

Leyton\LaravelCircuitBreaker\Transporters\Packet {#2939
    +result: "all is good",
    +status: Leyton\LaravelCircuitBreaker\CircuitStatus {#2943
        +name: "CLOSED",
        +value: "closed",
    },
    +success: true,
}

此模式的一个优点是防止系统在存在多个事务时执行不必要的操作。以下是使用示例

<?php

namespace App\Http\Controllers;

use Leyton\LaravelCircuitBreaker\Circuit;
use App\Services\LocationServiceClient;
use App\Services\PaymentGatewayClient;
use Illuminate\Http\Request;
use Exception;


class MakeOrderController extends Controller
{
    public function __construct(
        protected LocationServiceClient $locationServiceClient,
        protected PaymentGatewayClient $paymentGatewayClient,
        protected Circuit $Circuit,
    ) {
        
    }

    public function __invoke(Request $request)
    {
        $location = $request->get('location');
        $paymentDetails = $request->get('payment_details');
        $client = $request->get('client');

        if(!$this->circuit->available(['location-service', 'payment-service'])){
            return response()->json([
                'message' => 'Services are un-available, please retry later'
            ]);
        }
        
        $withdrawalPoint = $this->circuit->run("location-service", fn() => $this->locationServiceClient->getNearWithdrawalPoint($location));
        
        $payment = $this->circuit->run(
                "payment-service", 
                fn() => $this->paymentGatewayClient->processPayment($client, $order, $withdrawalPoint->result)
        );

    // ...
        return response()->json($data);
    }
}