Laravel’de Feature Flags ile Güvenli Yayın (Progressive Delivery) ve Hızlı Geri Dönüş
Yeni özellikleri kullanıcı bazında aç/kapat; kademeli yayınla, riskleri azalt, anında rollback yap.
Üretimde “tek seferde yayın” yerine kademeli yayın (progressive delivery) yapmak, hem hatayı sınırlı kitlede yakalamanı hem de gerektiğinde saniyeler içinde geri dönmeni sağlar. Bunu Laravel’de en pratik şekilde feature flag yaklaşımıyla kurabilirsin.
Neden Feature Flag?
- Risk azaltır: Yeni kod canlıda ama kapalı olabilir.
- Canary / yüzde bazlı yayın: %5 → %25 → %100.
- A/B deneyi ve pilot kullanıcılar: Belirli kullanıcılara aç.
- Anında rollback: Deploy geri almadan özelliği kapat.
Basit Flag Tasarımı: feature_flags Tablosu
Aşağıdaki yapı, “flag aktif mi?”, “kimlere açık?” ve “yüzde kaç kullanıcıya açık?” sorularını karşılar.
// migration (özet)
Schema::create('feature_flags', function ($table) {
$table->id();
$table->string('key')->unique();
$table->boolean('enabled')->default(false);
$table->unsignedTinyInteger('rollout_percentage')->default(0); // 0-100
$table->json('allowed_user_ids')->nullable(); // [1,2,3]
$table->timestamps();
});
Model:
class FeatureFlag extends Model
{
protected $fillable = ['key','enabled','rollout_percentage','allowed_user_ids'];
protected $casts = ['allowed_user_ids' => 'array', 'enabled' => 'boolean'];
}
Flag Kontrol Servisi (Cache’li)
DB’ye sürekli gitmemek için flag’i cache’lemek iyi olur.
use Illuminate\Support\Facades\Cache;
class Features
{
public function enabled(string $key, ?int $userId = null): bool
{
$flag = Cache::remember("feature:$key", 30, function () use ($key) {
return FeatureFlag::query()->where('key', $key)->first();
});
if (!$flag || !$flag->enabled) {
return false;
}
// Whitelist: belirli kullanıcılara kesin açık
if ($userId && is_array($flag->allowed_user_ids) && in_array($userId, $flag->allowed_user_ids, true)) {
return true;
}
// Yüzde bazlı rollout
$pct = (int) $flag->rollout_percentage;
if ($pct <= 0) return false;
if ($pct >= 100) return true;
// Deterministik dağıtım: aynı userId her zaman aynı sonuca gider
if (!$userId) return false;
$hash = crc32($key . ':' . $userId);
$bucket = $hash % 100; // 0-99
return $bucket < $pct;
}
public function flush(string $key): void
{
Cache::forget("feature:$key");
}
}
Deterministik “bucket” mantığı, kullanıcıların bir gün açık diğer gün kapalı görmesini engeller.
Kullanım Örneği: Controller/Blade
Yeni ödeme akışını sadece %10 kullanıcıya açalım:
public function checkout(Features $features)
{
$userId = auth()->id();
if ($features->enabled('new_checkout', $userId)) {
return view('checkout.v2');
}
return view('checkout.v1');
}
Blade içinde:
@if(app(Features::class)->enabled('new_nav', auth()->id()))
@include('partials.nav_v2')
@else
@include('partials.nav_v1')
@endif
Operasyonel İpuçları
- Admin ekranı ile
enabledverollout_percentagealanlarını anlık yönet. - Bir flag değişince ilgili cache’i temizle (ör. Observer veya admin action sonrası
flush). - Kritik işlerde (ödeme, stok) flag açıkken bile audit log tut.
- Flag sayısı artarsa: anahtar isimlendirmesi (
billing.new_checkout) ve yaşam döngüsü (kapanan flag’leri koddan temizleme) belirle.
Sonuç
Feature flag yaklaşımıyla Laravel projelerinde “deploy = risk” denkleminden çıkıp, kontrollü yayın + hızlı geri dönüş kazanırsın. Küçük bir tablo, cache ve deterministik rollout mantığıyla üretim güvenliğini ciddi şekilde artırmak mümkün.