Lập trình · 20/09/2026

Laravel Pennant: Triển khai feature flag và rollout tính năng an toàn

Deploy code và bật tính năng không nhất thiết phải xảy ra cùng lúc. Feature flag cho phép đưa code lên production ở trạng thái tắt, mở cho đội nội bộ, rollout từng nhóm người dùng và tắt nhanh khi có sự cố. Laravel Pennant cung cấp cách quản lý quy trình này bằng API gọn, scope rõ ràng và driver lưu trữ nhất quán.

Laravel Pennant: Triển khai feature flag và rollout tính năng an toàn

Deploy code và bật tính năng không nhất thiết phải xảy ra cùng lúc. Feature flag cho phép đưa code lên production ở trạng thái tắt, mở cho đội nội bộ, rollout từng nhóm người dùng và tắt nhanh khi có sự cố. Laravel Pennant cung cấp cách quản lý quy trình này bằng API gọn, scope rõ ràng và driver lưu trữ nhất quán.

Bài viết tập trung vào cách dùng Pennant có kỷ luật: định nghĩa cờ, chọn scope, rollout, kill switch, kiểm thử và quan trọng nhất là xóa cờ khi nó hoàn thành nhiệm vụ.

Feature flag giải quyết vấn đề gì?

Tình huốngCách feature flag hỗ trợ
Canary releaseMở cho nhân viên hoặc một nhóm nhỏ trước khi rollout rộng.
Trunk-based developmentMerge code chưa hoàn thiện nhưng giữ đường đi mới ở trạng thái tắt.
A/B testingTrả về biến thể có giá trị thay vì chỉ true/false.
Giảm rủi roTắt đường đi mới nhanh mà không cần rollback toàn bộ deployment.

Feature flag không thay thế phân quyền. Authorization trả lời người dùng được phép làm gì; feature flag quyết định trải nghiệm hoặc implementation nào đang được rollout.

Cài Laravel Pennant

composer require laravel/pennant
php artisan vendor:publish --provider="Laravel\Pennant\PennantServiceProvider"
php artisan migrate

Driver database là lựa chọn mặc định để lưu kết quả đã resolve. Driver array phù hợp cho test hoặc trường hợp không cần lưu qua request.

Định nghĩa cờ đầu tiên

use App\Models\User;
use Illuminate\Support\Lottery;
use Laravel\Pennant\Feature;

Feature::define('checkout-v2', fn (User $user) => match (true) {
    $user->isInternalTeamMember() => true,
    $user->hasSupportHold() => false,
    default => Lottery::odds(1, 20),
});

Lần đầu cờ được kiểm tra cho một scope, Pennant resolve rồi lưu kết quả. Điều này giúp cùng một người dùng không bị chuyển qua lại ngẫu nhiên giữa hai trải nghiệm ở mỗi request.

Chọn scope theo đơn vị rollout

Scope thường là User, nhưng ứng dụng SaaS có thể cần rollout theo Team hoặc Organization để mọi thành viên cùng thấy một trải nghiệm.

if (Feature::for($user->team)->active('billing-v2')) {
    return redirect()->route('billing.v2');
}

Hãy chọn scope trước khi rollout. Đổi từ user sang team giữa chừng có thể tạo tập kết quả lưu trữ mới và khiến hành vi khó giải thích.

Dùng class-based feature cho logic quan trọng

final class CheckoutV2
{
    public function before(User $user): mixed
    {
        if (config('features.checkout_v2_disabled')) {
            return $user->isInternalTeamMember();
        }

        return null;
    }

    public function resolve(User $user): bool
    {
        return $user->created_at->isAfter(now()->subMonths(3));
    }
}

before() chạy trước giá trị đã lưu và có thể đóng vai trò kill switch. Khi phát hiện lỗi, đội vận hành tắt tính năng cho phần lớn người dùng mà không làm mất assignment cũ; sau khi sửa, có thể mở lại đúng nhóm trước đó.

Kiểm tra cờ ở đúng lớp

return Feature::for($user)->active('checkout-v2')
    ? $newCheckout->handle($cart)
    : $legacyCheckout->handle($cart);

Đặt check gần điểm rẽ hành vi chính giúp hai đường đi dễ đọc và dễ xóa. Tránh rải cùng một tên cờ ở controller, view, job và service nếu có thể gom quyết định tại một lớp điều phối.

Ở Blade, có thể dùng directive @feature. Với route cần chặn toàn bộ, Pennant cung cấp middleware kiểm tra cờ đang active.

Rich value cho nhiều biến thể

Feature::define('checkout-button', fn (User $user) =>
    $user->country_code === 'VN' ? 'compact' : 'standard'
);

$variant = Feature::value('checkout-button');

Rich value phù hợp với biến thể giao diện hoặc tham số rollout. Tên biến thể nên là tập giá trị nhỏ, ổn định và được analytics ghi nhận; không nên biến feature store thành nơi chứa cấu hình nghiệp vụ tùy ý.

Tránh N+1 khi kiểm tra nhiều scope

Feature::for($users)->load(['notifications-beta']);

foreach ($users as $user) {
    if (Feature::for($user)->active('notifications-beta')) {
        // ...
    }
}

Pennant cache kết quả trong một request, nhưng vòng lặp qua nhiều user vẫn có thể tạo nhiều truy vấn. Eager loading giúp đọc trước các giá trị cần thiết.

Kiểm thử cả hai đường đi

Feature::define('checkout-v2', true);

$this->actingAs($user)
    ->post('/checkout', $payload)
    ->assertRedirect('/orders/success');

Feature::define('checkout-v2', false);

Test cần bao phủ cả trạng thái bật và tắt cho đến khi đường cũ bị xóa. Với class-based feature, có thể fake hoặc định nghĩa lại kết quả trong test để tránh phụ thuộc assignment ngẫu nhiên.

Thiết kế quy trình rollout

  1. Deploy schema và code tương thích với cả đường cũ lẫn đường mới.
  2. Mở cho đội nội bộ; theo dõi lỗi, latency và chỉ số nghiệp vụ.
  3. Mở cho một cohort nhỏ, ổn định theo scope.
  4. Tăng dần tỷ lệ khi số liệu đạt ngưỡng đã đặt trước.
  5. Kích hoạt cho tất cả và theo dõi thêm một khoảng an toàn.
  6. Xóa đường code cũ, định nghĩa cờ, dữ liệu cờ và dashboard tạm thời.

Migration database phải tương thích ngược trong suốt rollout. Tắt feature flag không thể cứu hệ thống nếu deployment đã xóa cột mà đường code cũ vẫn cần.

Dọn feature flag sau khi rollout

php artisan pennant:purge checkout-v2

Mỗi cờ nên có owner, mục tiêu, ngày tạo và điều kiện xóa. Cờ tồn tại quá lâu làm tăng số nhánh logic, nhân đôi test và khiến việc đọc code khó hơn. Feature flag là công cụ chuyển đổi, không phải trạng thái vĩnh viễn mặc định.

Checklist áp dụng Pennant

  • Tên cờ mô tả hành vi, không gắn chặt với ticket ngắn hạn.
  • Scope phù hợp với đơn vị rollout: user, team hoặc global.
  • Có kill switch cho thay đổi rủi ro cao.
  • Metrics phân tách theo biến thể và có ngưỡng dừng rollout.
  • Test cả đường bật và tắt.
  • Schema tương thích với hai đường code trong giai đoạn chuyển đổi.
  • Có owner và kế hoạch xóa cờ.

Nguồn tham khảo

Thảo luận

Bình luận 0

Đăng nhập để bình luận

Bạn cần có tài khoản để tham gia thảo luận và trả lời độc giả khác.

Đăng nhậpĐăng ký

Chưa có bình luận. Hãy là người đầu tiên chia sẻ ý kiến.