Installation:
composer require godruoyi/php-snowflake
For Redis/Predis/Swoole support, install additional dependencies as needed (see README).
First Use Case: Generate a basic Snowflake ID in a Laravel controller or service:
use Godruoyi\Snowflake\Snowflake;
$snowflake = new Snowflake();
$id = $snowflake->id(); // e.g., 1537200202186752
Where to Look First:
datacenterId and workerId (0–31) if not set (since v3.2.0).setStartTimeStamp(): Optimize timestamp range (e.g., strtotime('2023-01-01') * 1000).setSequenceResolver(): Choose concurrency strategy (e.g., RedisSequenceResolver for distributed systems).AppServiceProvider (see Advanced).Basic ID Generation:
$snowflake = new Snowflake($datacenterId, $workerId);
$id = $snowflake->id(); // 64-bit integer
Str::uuid() or DB::raw('AUTO_INCREMENT') in models/services.Laravel Service Container:
// config/snowflake.php
return [
'start_timestamp' => strtotime('2023-01-01') * 1000,
'datacenter_id' => env('SNOWFLAKE_DATACENTER_ID', 1),
'worker_id' => env('SNOWFLAKE_WORKER_ID', 1),
];
// AppServiceProvider.php
$this->app->singleton(Snowflake::class, function ($app) {
$config = config('snowflake');
$snowflake = new Snowflake($config['datacenter_id'], $config['worker_id']);
return $snowflake->setStartTimeStamp($config['start_timestamp']);
});
Distributed Systems:
// Using Redis for concurrency safety
$snowflake = new Snowflake();
$snowflake->setSequenceResolver(new RedisSequenceResolver($redisClient, 'snowflake:lock'));
$id = $snowflake->id();
FileLockResolver) are impractical.Sonyflake for Non-Time-Based IDs:
$sonyflake = new Sonyflake();
$id = $sonyflake->id(); // Non-time-based, 64-bit
Database Schemas:
Use BIGINT UNSIGNED for storage (e.g., id bigint unsigned primary key).
CREATE TABLE users (
id BIGINT UNSIGNED NOT NULL PRIMARY KEY,
name VARCHAR(255),
created_at TIMESTAMP
);
Event Sourcing: Embed Snowflake IDs in event payloads for traceability:
$event = new UserRegisteredEvent(
id: $snowflake->id(),
userId: $user->id,
metadata: [...]
);
Caching: Cache Snowflake instances in Laravel’s cache store for high-throughput scenarios:
$snowflake = Cache::remember('snowflake_instance', 3600, function () {
return new Snowflake($datacenterId, $workerId);
});
Testing:
Mock the SequenceResolver interface for unit tests:
$mockResolver = $this->createMock(SequenceResolver::class);
$mockResolver->method('sequence')->willReturn(42);
$snowflake->setSequenceResolver($mockResolver);
Timestamp Skew:
setStartTimeStamp() isn’t configured, the package uses the current time, risking collisions if the system clock is adjusted.$snowflake->setStartTimeStamp(strtotime('2023-01-01') * 1000);
Sequence Collisions:
RandomSequenceResolver is not thread-safe and may cause duplicates in concurrent environments.FileLockResolver, RedisSequenceResolver, or LaravelSequenceResolver for production.$snowflake->setSequenceResolver(new FileLockResolver('/tmp/snowflake.lock'));
Datacenter/Worker ID Limits:
31). Exceeding this throws an exception.$datacenterId = max(0, min(31, env('SNOWFLAKE_DATACENTER_ID', 1)));
Sonyflake vs. Snowflake:
PHP 8.1+ Requirement:
ID Parsing:
Use the parse() method to extract components from an ID:
$parsed = $snowflake->parse($id);
// Returns: [
// 'timestamp' => 1537200202186,
// 'datacenterId' => 1,
// 'workerId' => 1,
// 'sequence' => 752
// ]
Clock Drift: If IDs appear out of order, check system time synchronization:
timedatectl status # Linux
setStartTimeStamp() to account for drift.Custom Sequence Resolver:
Implement Godruoyi\Snowflake\SequenceResolver for bespoke concurrency control:
class DatabaseSequenceResolver implements SequenceResolver
{
public function sequence(int $currentMillisecond): int
{
return DB::table('snowflake_sequences')
->where('millisecond', $currentMillisecond)
->increment('sequence', 1);
}
}
Time Resolver: Override timestamp logic (e.g., for testing or custom clocks):
$snowflake->setTimeResolver(function () {
return time() * 1000; // Milliseconds
});
Laravel Cache Prefix:
Customize the cache key prefix for LaravelSequenceResolver:
$resolver = new LaravelSequenceResolver($cache, 'custom_');
$snowflake->setSequenceResolver($resolver);
Batch Generation: Pre-generate IDs in bulk for offline processing (e.g., data migration):
$ids = [];
for ($i = 0; $i < 1000; $i++) {
$ids[] = $snowflake->id();
}
Avoid Lock Contention:
For high-throughput systems, use RedisSequenceResolver with a dedicated Redis instance:
$redis = Redis::connection('snowflake');
$snowflake->setSequenceResolver(new RedisSequenceResolver($redis, 'snowflake:seq'));
Swoole Optimization:
In Swoole coroutines, use SwooleSequenceResolver for lock-free concurrency:
$snowflake->setSequenceResolver(new SwooleSequenceResolver());
How can I help you explore Laravel packages today?