Weave Code
Code Weaver
Helps Laravel developers discover, compare, and choose open-source packages. See popularity, security, maintainers, and scores at a glance to make better decisions.
Feedback
Share your thoughts, report bugs, or suggest improvements.
Subject
Message

Bits Laravel Package

glhd/bits

Generate unique 64-bit IDs in PHP for distributed systems. Create Twitter Snowflake, Sonyflake, or custom bit-sequence identifiers. Configure worker/datacenter IDs and a custom epoch to avoid collisions across servers.

View on GitHub
Deep Wiki
Context7

Getting Started

Minimal Setup

  1. Install the package:

    composer require glhd/bits
    
  2. Configure environment variables (critical for distributed systems):

    BITS_WORKER_ID=1          # Unique per worker (0-31)
    BITS_DATACENTER_ID=1      # Unique per datacenter (0-31)
    BITS_EPOCH=2023-01-01     # Default; adjust if testing with past dates
    
  3. First use case: Generate a Snowflake ID in a controller or service:

    use Glhd\Bits\Snowflake;
    
    $id = Snowflake::make()->id(); // Returns int (e.g., 65898467809951744)
    

Key Starting Points

  • Global helpers: snowflake_id() (shorthand) or sonyflake().
  • Eloquent integration: Use HasSnowflakes trait for auto-generated IDs.
  • Timestamp extraction: $snowflake->toCarbon() for time-based queries.

Implementation Patterns

Core Workflows

1. Model Integration

use Glhd\Bits\Database\HasSnowflakes;

class User extends Model
{
    use HasSnowflakes; // Auto-generates Snowflake on create

    protected $casts = [
        'legacy_id' => Snowflake::class, // Casts DB int to Snowflake object
    ];
}

2. Time-Based Queries

Replace created_at comparisons with Snowflake IDs:

// Instead of:
User::where('created_at', '>', now()->subDays(7));

// Use:
$userIdThreshold = app(\Glhd\Bits\Snowflake::class)
    ->firstForTimestamp(now()->subDays(7))
    ->id();

User::where('id', '>', $userIdThreshold);

3. Livewire Property Synth

Register in AppServiceProvider:

use Glhd\Bits\Support\Livewire\SnowflakeSynth;

public function boot(): void
{
    Livewire::propertySynthesizer(SnowflakeSynth::class);
}

Now use in components:

public $snowflakeId;

public function mount()
{
    $this->snowflakeId = snowflake_id(); // Synthesized as Snowflake object
}

4. Custom Bit Allocation

Extend Bits for non-Snowflake/Sonyflake formats:

use Glhd\Bits\Bits;

class CustomBits extends Bits
{
    protected static function getBitAllocation(): array
    {
        return [
            'timestamp' => 35,
            'worker'    => 10,
            'sequence'  => 19,
        ];
    }
}

Integration Tips

  • Database: Use BIGINT columns (signed/unsigned depends on your bit allocation).
  • Testing: Use Snowflake::setTestNow() instead of Carbon::setTestNow():
    Snowflake::setTestNow(now()->subHours(1));
    
  • JavaScript: Cast IDs to strings to avoid Number precision issues:
    $snowflake->toString(); // "65898467809951744"
    

Gotchas and Tips

Pitfalls

  1. Worker/Datacenter Limits:

    • Issue: Only 1024 workers (32 datacenters × 32 workers each) can run simultaneously.
    • Fix: Use BITS_WORKER_ID and BITS_DATACENTER_ID environment variables. For Lambda/Vapor, implement a locking mechanism (e.g., Redis) to avoid collisions.
  2. Epoch Misconfiguration:

    • Issue: Setting BITS_EPOCH to a future date throws an exception.
    • Fix: Validate epoch during deployment:
      if (now()->lt(config('bits.epoch'))) {
          throw new \RuntimeException('Epoch must be in the past.');
      }
      
  3. Sequence Collisions:

    • Issue: High-frequency ID generation may exhaust the 12-bit sequence (4096 IDs/sec).
    • Fix: Use a distributed sequence resolver (e.g., Redis):
      $resolver = new \Glhd\Bits\CacheSequenceResolver(
          app('cache.store'),
          'bits:sequence'
      );
      
  4. Livewire Serialization:

    • Issue: Custom Bits classes may not serialize correctly.
    • Fix: Use BitsSynth instead of SnowflakeSynth for non-standard formats.

Debugging Tips

  • Validate IDs:

    $snowflake = Snowflake::fromId($idFromDb);
    if (!$snowflake) {
        throw new \InvalidArgumentException('Invalid Snowflake ID.');
    }
    
  • Inspect Bit Structure:

    $snowflake = Snowflake::make();
    dd([
        'timestamp'   => $snowflake->timestamp,
        'datacenter'  => $snowflake->datacenter_id,
        'worker'      => $snowflake->worker_id,
        'sequence'    => $snowflake->sequence,
    ]);
    
  • Check for Time Skew:

    $now = now();
    $snowflakeNow = Snowflake::make()->toCarbon();
    if ($now->diffInSeconds($snowflakeNow) > 1) {
        // Clock skew detected!
    }
    

Extension Points

  1. Custom Resolvers: Override SequenceResolver for custom backends (e.g., database):

    class DatabaseSequenceResolver implements SequenceResolver
    {
        public function next(): int { /* ... */ }
        public function reset(): void { /* ... */ }
    }
    
  2. Blueprint Macros: Extend Laravel’s query builder:

    use Glhd\Bits\Support\BlueprintMacros;
    
    BlueprintMacros::register();
    // Now use `whereSnowflakeAfter($timestamp)` in queries.
    
  3. Event Dispatching: Hook into ID generation:

    Snowflake::created(function (Snowflake $snowflake) {
        event(new SnowflakeGenerated($snowflake));
    });
    

Performance Quirks

  • Cold Starts: First ID generation in a request may have a ~1ms latency due to sequence initialization.
  • Redis Overhead: Cache-based sequence resolvers add ~500µs per ID in high-latency environments.
  • PHP Workers: Ensure pcntl or pthreads are disabled if using BITS_WORKER_ID in multi-process setups.

Laravel-Specific Notes

  • Migration Compatibility: Use Schema::bigIncrements() for new tables (avoids signed/unsigned conflicts).

  • Model Events: Listen for retrieved/saved to log Snowflake metadata:

    User::saved(function (User $user) {
        logger()->info('Generated Snowflake', [
            'id' => $user->id,
            'timestamp' => $user->id->toCarbon(),
        ]);
    });
    
  • Testing:

    // Reset test time globally
    Snowflake::setTestNow(now()->subDay());
    
Weaver

How can I help you explore Laravel packages today?

Conversation history is not saved when not logged in.
Prompt
Add packages to context
No packages found.
codraw/entity-migrator
codraw/doctrine-extra
codraw/aws-tool-kit
codraw/validator
codraw/workflow
codraw/open-api
codraw/cron-job
codraw/process
codraw/log
nexmo/api-specification
capell-app/block-library
axium/identity
cetria/laravel-dummy-models
cetria/reflection-helper
agropredict/sso-auth-bundle
evolvestudio/spam-protection
datacore/hub-sdk
develia/commons
cuci/prototurk-sdk
cuci/prototurk-sdk-symfony