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 for distributed systems in PHP. Create Twitter Snowflake, Sonyflake, or custom bit-sequence identifiers with configurable worker/datacenter IDs and epoch for compact, time-ordered, collision-resistant IDs across multiple servers.

View on GitHub
Deep Wiki
Context7

Getting Started

Minimal Steps

  1. Installation:

    composer require glhd/bits
    
  2. Configure Environment: Add to .env:

    BITS_WORKER_ID=1
    BITS_DATACENTER_ID=1
    

    (Replace values with unique IDs for your worker/datacenter. Ensure no duplicates across servers.)

  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)
    

    Or use the helper:

    $id = snowflake_id(); // Same result
    
  4. Verify Configuration: Check the generated ID’s metadata:

    $snowflake = Snowflake::make();
    echo $snowflake->timestamp; // Unix timestamp (relative to BITS_EPOCH)
    echo $snowflake->worker_id;  // Your configured worker ID
    

Where to Look First


Implementation Patterns

Core Workflows

1. Model Integration (Most Common)

Use HasSnowflakes to auto-generate IDs:

use Glhd\Bits\Database\HasSnowflakes;

class Order extends Model
{
    use HasSnowflakes; // Auto-generates Snowflake on create
}
  • Pros: Zero boilerplate, works with migrations/seeders.
  • Cons: Requires id column to be bigint unsigned.

Custom Casts:

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

2. Time-Based Queries

Replace created_at filters with Snowflake IDs:

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

// Use:
$minId = app(\Glhd\Bits\Snowflake::class)->firstForTimestamp(now()->subDays(7));
User::where('id', '>', $minId);
  • Performance: Avoids index scans on created_at; leverages primary key.
  • Edge Case: Ensure BITS_EPOCH is before your earliest data.

3. Distributed ID Generation

Multi-server Setup:

  • Assign unique BITS_DATACENTER_ID (0–31) per region.
  • Assign unique BITS_WORKER_ID (0–31) per server in the same datacenter.
  • Example: Datacenter 1 (US-East), Worker 5 (App Server 1).

Lambda/Vapor Workaround: Use a centralized ID service (e.g., Redis) or implement locking to avoid collisions:

$lock = app(\Illuminate\Cache\Lock::class)->get('bits-lock');
if ($lock->get()) {
    $id = snowflake_id();
}

4. Livewire Integration

Enable client-side ID generation:

// AppServiceProvider.php
Livewire::propertySynthesizer(\Glhd\Bits\Support\Livewire\SnowflakeSynth::class);
  • Use Case: Generate IDs in Livewire components without backend calls.
  • Limitation: Requires server-side sync for uniqueness (use HasSnowflakes for DB storage).

5. Custom ID Formats

Extend Bits for Sonyflake or custom layouts:

use Glhd\Bits\Bits;

$sonyflake = Bits::sonyflake()->make();
  • When to Use: Sonyflake’s 39-bit timestamp allows longer sequences (better for high-throughput systems).

Integration Tips

Database

  • Schema: Use bigint unsigned for Snowflake columns (64-bit range: 0 to 18,446,744,073,709,551,615).
  • Indexes: Snowflake IDs are sortable by time; index them for time-based queries.

API/JSON

  • JavaScript Compatibility: Cast IDs to strings for frontend:
    return response()->json(['id' => (string) $snowflake]);
    
    • Why: JavaScript’s Number.MAX_SAFE_INTEGER is 2^53 - 1 (~9e15). Snowflakes exceed this.

Testing

  • Time Travel: Use Bits::setTestNow() instead of Carbon::setTestNow():
    Bits::setTestNow(now()->subDays(5)); // Overrides Snowflake timestamps
    
    • Critical: Avoids conflicts with Carbon’s global test time.

Caching

  • Sequence Resolution: For high-throughput systems, use a CacheSequenceResolver:
    $bits = Bits::snowflake()->withSequenceResolver(
        new \Glhd\Bits\CacheSequenceResolver(cache())
    );
    
    • Use Case: Reduces database load by caching sequence numbers.

Gotchas and Tips

Pitfalls

  1. Worker/Datacenter ID Collisions

    • Symptom: Duplicate IDs or InvalidArgumentException ("Worker ID must be unique").
    • Fix: Audit all servers/datacenters to ensure no overlapping BITS_WORKER_ID or BITS_DATACENTER_ID.
    • Tool: Use php artisan tinker to verify:
      echo Snowflake::make()->worker_id; // Should match .env
      
  2. Epoch Mismatches

    • Symptom: IDs appear in the future or past unexpectedly.
    • Cause: BITS_EPOCH set to a date after your first ID was generated.
    • Fix: Set BITS_EPOCH to a date before your earliest expected ID (e.g., 2020-01-01).
  3. Lambda/Vapor Concurrency

    • Symptom: Random InvalidArgumentException in serverless environments.
    • Root Cause: Multiple Lambda instances or Vapor workers may generate IDs simultaneously.
    • Workaround:
      • Use a centralized ID service (e.g., Redis).
      • Implement application-level locking:
        $lock = app(\Illuminate\Cache\Lock::class)->get('bits-lock-' . request()->ip());
        if ($lock->get()) {
            $id = snowflake_id();
        }
        
  4. Livewire ID Uniqueness

    • Symptom: Duplicate IDs in Livewire components.
    • Cause: Client-side generation without server validation.
    • Fix: Use HasSnowflakes for DB storage and validate uniqueness:
      $this->validate(['id' => 'required|unique:orders,id']);
      
  5. JavaScript ID Truncation

    • Symptom: Snowflake IDs appear as 9e+18 in JavaScript.
    • Fix: Always cast to string:
      // PHP
      return (string) $snowflake;
      
      // JavaScript
      const id = '65898467809951744'; // String, not number
      

Debugging Tips

  1. Inspect ID Components

    $snowflake = Snowflake::make();
    dd([
        'id' => $snowflake->id,
        'timestamp' => $snowflake->toCarbon(),
        'worker' => $snowflake->worker_id,
        'datacenter' => $snowflake->datacenter_id,
        'sequence' => $snowflake->sequence,
    ]);
    
  2. Validate Epoch

    php artisan tinker
    >>> Bits::snowflake()->epoch->format('Y-m-d')
    // Should match your .env BITS_EPOCH
    
  3. Check for Future IDs

    $now = now();
    $snowflake = Snowflake::make();
    if ($s
    
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.
davejamesmiller/laravel-breadcrumbs
artisanry/parsedown
christhompsontldr/phpsdk
enqueue/dsn
bunny/bunny
enqueue/test
enqueue/null
enqueue/amqp-tools
milesj/emojibase
bower-asset/punycode
bower-asset/inputmask
bower-asset/jquery
bower-asset/yii2-pjax
laravel/nova
spatie/laravel-mailcoach
spatie/laravel-superseeder
laravel/liferaft
nst/json-test-suite
danielmiessler/sec-lists
jackalope/jackalope-transport