Harnessing Controlled Randomness with Laravel's Lottery
In the world of web development, there are times when you need to introduce controlled randomness into your application. Whether it's for A/B testing, gradual feature rollouts, or sampling large datasets, Laravel's Lottery class provides an elegant solution. Let's dive into how you can leverage this powerful feature in your Laravel projects.
Basic Usage of Lottery
At its core, Laravel's Lottery allows you to execute code based on specified odds. Here's a simple example:
use Illuminate\Support\Lottery;
Lottery::odds(1, 20)
->winner(fn () => $user->won())
->loser(fn () => $user->lost())
->choose();
In this case, there's a 1 in 20 chance that the winner callback will be executed, and a 19 in 20 chance for the loser callback.
Lottery with Database Queries
One powerful application of Lottery is in database query monitoring. You can use it to report only a small percentage of slow queries:
use Carbon\CarbonInterval;
use Illuminate\Support\Facades\DB;
use Illuminate\Support\Lottery;
DB::whenQueryingForLongerThan(
CarbonInterval::seconds(2),
Lottery::odds(1, 100)->winner(fn () => report('Querying > 2 seconds.')),
);
This setup will report only 1% of queries that take longer than 2 seconds, helping you to monitor performance without overwhelming your logging system.
Gradual Feature Rollout
Lottery is perfect for implementing gradual feature rollouts:
if (Lottery::odds(1, 10)->choose()) {
return view('new-feature');
} else {
return view('old-feature');
}
This code will show the new feature to 10% of users, allowing you to test it with a small subset of your user base.
A/B Testing
You can easily implement A/B testing using Lottery:
$version = Lottery::odds(1, 2)->choose() ? 'A' : 'B';
return view("landing-page-{$version}");
This will randomly assign users to version A or B of your landing page with equal probability.
Sampling Large Datasets
When dealing with big data, you might want to process only a sample of your dataset:
User::chunk(1000, function ($users) {
foreach ($users as $user) {
Lottery::odds(1, 100)->winner(function () use ($user) {
ProcessUserData::dispatch($user);
});
}
});
This code will process data for approximately 1% of your users, which can be useful for generating reports or running intensive computations on a representative sample.
Testing Lotteries
Laravel provides methods to make testing Lottery-based code straightforward:
use Illuminate\Support\Lottery;
// In your test method
public function testFeatureRollout()
{
Lottery::alwaysWin();
$response = $this->get('/feature');
$response->assertViewIs('new-feature');
Lottery::alwaysLose();
$response = $this->get('/feature');
$response->assertViewIs('old-feature');
}
You can also set up a sequence of wins and losses:
Lottery::fix([true, false, true]);
This will make the lottery win, then lose, then win again, before returning to normal behavior.
Real-World Example: Error Sampling in Production
In a high-traffic production environment, you might want to sample only a portion of errors to prevent overwhelming your error tracking service:
use Illuminate\Support\Facades\App;
use Illuminate\Support\Lottery;
class Handler extends ExceptionHandler
{
public function report(Throwable $e)
{
if (App::environment('production')) {
Lottery::odds(1, 100)->winner(function () use ($e) {
parent::report($e);
});
} else {
parent::report($e);
}
}
}
This setup will report only 1% of errors in production, while still reporting all errors in other environments.
Laravel's Lottery class provides a powerful and flexible way to introduce controlled randomness into your applications. Whether you're gradually rolling out features, conducting A/B tests, or sampling large datasets, Lottery offers an elegant solution. By leveraging this feature, you can create more sophisticated, data-driven applications while maintaining clean, expressive code.
If this guide was helpful to you, subscribe to my daily newsletter and give me a follow on X/Twitter. It helps a lot!