Artikel sebelumnya membahas konsep Concurrency di Laravel 12. Artikel ini fokus pada implementasi: studi kasus nyata bagaimana Concurrency bisa mempercepat aplikasi secara signifikan.
Studi Kasus 1: Dashboard dengan Banyak Data Source
Dashboard admin yang butuh data dari beberapa tabel berbeda. Ini biasanya jadi bottleneck karena diquery satu per satu.
Sebelum (sequential — sekitar 800ms):
public function dashboard()
{
$totalOrders = Order::thisMonth()->count(); // ~200ms
$totalRevenue = Order::thisMonth()->sum('total'); // ~200ms
$pendingOrders = Order::where('status', 'pending')->count(); // ~150ms
$newCustomers = User::thisMonth()->count(); // ~150ms
$topProducts = Product::topSelling(5)->get(); // ~100ms
return view('dashboard', compact(...));
}
Sesudah (paralel — sekitar 200ms):
use IlluminateSupportFacadesConcurrency;
public function dashboard()
{
[$totalOrders, $totalRevenue, $pendingOrders, $newCustomers, $topProducts] =
Concurrency::run([
fn() => Order::thisMonth()->count(),
fn() => Order::thisMonth()->sum('total'),
fn() => Order::where('status', 'pending')->count(),
fn() => User::thisMonth()->count(),
fn() => Product::topSelling(5)->get(),
]);
return view('dashboard', compact(
'totalOrders', 'totalRevenue', 'pendingOrders', 'newCustomers', 'topProducts'
));
}
Studi Kasus 2: Multiple API Calls
Halaman product detail yang butuh data dari beberapa API eksternal:
use IlluminateSupportFacadesConcurrency;
public function productDetail(Product $product): View
{
[$reviews, $stock, $shippingOptions] = Concurrency::run([
fn() => $this->reviewApi->getProductReviews($product->id), // API 1
fn() => $this->inventoryApi->getStock($product->sku), // API 2
fn() => $this->shippingApi->getOptions($product->weight), // API 3
]);
return view('products.detail', compact('product', 'reviews', 'stock', 'shippingOptions'));
}
Kalau masing-masing API butuh 500ms, tanpa concurrency total 1.5 detik. Dengan concurrency, cukup ~500ms.
Studi Kasus 3: Defer untuk Aksi Non-Blocking
User logout — beberapa aksi perlu terjadi tapi tidak perlu selesai sebelum response dikirim:
use IlluminateSupportFacadesConcurrency;
public function logout(Request $request): RedirectResponse
{
$user = $request->user();
Auth::logout();
$request->session()->invalidate();
$request->session()->regenerateToken();
// Jalankan setelah response dikirim
Concurrency::defer([
fn() => $this->activityLog->record($user, 'logout'),
fn() => $this->deviceTokenService->revokeAll($user),
fn() => $this->sessionCleanup->cleanup($user),
]);
return redirect('/');
}
Studi Kasus 4: Generate Laporan Parallel
Generate beberapa bagian laporan sekaligus lalu gabungkan:
public function generateAnnualReport(int $year): array
{
[$salesData, $customerData, $productData, $regionData] = Concurrency::run([
fn() => $this->salesReport->compile($year),
fn() => $this->customerReport->compile($year),
fn() => $this->productReport->compile($year),
fn() => $this->regionReport->compile($year),
]);
return [
'year' => $year,
'sales' => $salesData,
'customers' => $customerData,
'products' => $productData,
'regions' => $regionData,
'generated_at' => now()->toIso8601String(),
];
}
Error Handling di Concurrency
Kalau salah satu closure melempar exception, Concurrency akan meneruskan exception tersebut:
use IlluminateSupportFacadesConcurrency;
try {
[$data1, $data2] = Concurrency::run([
fn() => riskyApiCall(),
fn() => anotherApiCall(),
]);
} catch (Exception $e) {
// Handle error — biasanya fallback ke data cached atau default
Log::warning("Concurrency error: {$e->getMessage()}");
[$data1, $data2] = [getFromCache('data1'), getFromCache('data2')];
}
Kapan Tidak Pakai Concurrency
Jangan pakai untuk operasi yang sangat cepat. Overhead membuka child process (~50-100ms) lebih mahal dari manfaatnya kalau setiap closure selesai dalam 5ms.
Gunakan untuk operasi yang masing-masing butuh 100ms ke atas, terutama I/O seperti HTTP request, query database, atau baca file besar.
Baca Juga
Butuh tim yang bantu optimasi performa aplikasi Laravel Anda? Lihat layanan pengembangan aplikasi kami.
Leave a Reply