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

Seal Read Write Adapter Laravel Package

cmsig/seal-read-write-adapter

SEAL Read Write Adapter lets you use separate search adapters for reads and writes, enabling reindexing without downtime. Combine any AdapterInterface implementations (e.g., Elasticsearch) and configure via DSN for your framework.

View on GitHub
Deep Wiki
Context7

Getting Started

Minimal Setup

  1. Install Dependencies:

    composer require cmsig/seal cmsig/seal-read-write-adapter
    
  2. Define Adapters: Create separate instances for read and write operations (e.g., Elasticsearch, PostgreSQL, etc.):

    $readAdapter = new \CmsIg\Seal\Adapter\Elasticsearch\ElasticsearchAdapter(
        $readClientConfig
    );
    $writeAdapter = new \CmsIg\Seal\Adapter\Elasticsearch\ElasticsearchAdapter(
        $writeClientConfig
    );
    
  3. Wrap with ReadWriteAdapter:

    use CmsIg\Seal\Adapter\ReadWrite\ReadWriteAdapter;
    $adapter = new ReadWriteAdapter($readAdapter, $writeAdapter);
    
  4. Initialize SEAL Engine:

    $engine = new \CmsIg\Seal\Engine($adapter, $schema);
    

First Use Case

Zero-Downtime Reindexing:

  • Use the writeAdapter to index new/updated data into a staging index (or separate DB).
  • Use the readAdapter to serve queries from the live index (or primary DB).
  • Once reindexing is complete, swap the readAdapter to point to the new index.

Implementation Patterns

Workflow: Read-Write Separation

  1. Write Operations:

    • All create, update, and delete calls route to $writeAdapter.
    • Example:
      $engine->create($document); // Writes to $writeAdapter
      
  2. Read Operations:

    • All search, get, and exists calls route to $readAdapter.
    • Example:
      $results = $engine->search($query); // Reads from $readAdapter
      
  3. Synchronization:

    • Use a background job (e.g., Laravel Queues) to sync $writeAdapter$readAdapter asynchronously.
    • Example job:
      public function handle() {
          $documents = $writeAdapter->getUnsyncedDocuments();
          foreach ($documents as $doc) {
              $readAdapter->upsert($doc);
          }
      }
      

Integration Tips

  • Laravel Service Providers: Bind adapters and the ReadWriteAdapter to the container:

    $this->app->singleton('readAdapter', fn() => new ElasticsearchAdapter($readConfig));
    $this->app->singleton('writeAdapter', fn() => new ElasticsearchAdapter($writeConfig));
    $this->app->singleton('seal.adapter', fn($app) =>
        new ReadWriteAdapter($app['readAdapter'], $app['writeAdapter'])
    );
    
  • Configuration: Use environment variables for adapter-specific configs:

    SEAL_READ_URL=elasticsearch://read-host:9200
    SEAL_WRITE_URL=elasticsearch://write-host:9200
    
  • Fallback Logic: Implement a fallback to $writeAdapter for reads during sync failures:

    $adapter = new ReadWriteAdapter($readAdapter, $writeAdapter, true); // Enable fallback
    

Gotchas and Tips

Pitfalls

  1. Stale Reads:

    • Issue: $readAdapter may return outdated data if not synced.
    • Fix: Avoid partial updates based on read data. Always fetch fresh data from $writeAdapter before updates.
  2. Adapter Inconsistency:

    • Issue: $readAdapter and $writeAdapter might have different schemas or mappings.
    • Fix: Validate schemas match or use a migration tool (e.g., Laravel Migrations) to align them.
  3. Performance Overhead:

    • Issue: Dual adapters double the I/O load.
    • Fix: Use connection pooling (e.g., Elasticsearch bulk requests) or batch syncs.

Debugging

  • Log Adapter Calls: Decorate adapters to log operations:

    $readAdapter = new \CmsIg\Seal\Adapter\LoggingAdapter($readAdapter);
    
  • Verify Sync Status: Add a health check endpoint:

    Route::get('/sync-status', function () {
        return [
            'read_write_lag' => $writeAdapter->count() - $readAdapter->count(),
        ];
    });
    

Extension Points

  1. Custom Sync Logic: Override ReadWriteAdapter to add pre/post-sync hooks:

    class CustomReadWriteAdapter extends ReadWriteAdapter {
        public function sync() {
            $this->preSync();
            parent::sync();
            $this->postSync();
        }
    }
    
  2. Multi-Write Support: Use MultiAdapter (mentioned in README) to write to both adapters atomically:

    $multiAdapter = new \CmsIg\Seal\Adapter\MultiAdapter([$readAdapter, $writeAdapter]);
    
  3. Adapter-Specific Features: Leverage adapter-specific optimizations (e.g., Elasticsearch’s refresh parameter):

    $writeAdapter = new ElasticsearchAdapter($config, ['refresh' => 'false']);
    

Config Quirks

  • DSN Format: The multi:// and read-write:// DSNs are experimental. Prefer explicit instantiation for reliability.
  • Thread Safety: Ensure adapters are stateless or use connection pooling to avoid race conditions in concurrent environments.
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.
directorytree/privacy-filter-classifier
directorytree/privacy-filter
datacore/hub-sdk
develia/commons
cuci/prototurk-sdk
cuci/prototurk-sdk-symfony
develia/geo-bundle
dreamzy/livewire-charts
touchestate-sdk/php-sdk
22h/doctrine-garbage-collection-bundle
agtp/agtp-php
agtp/mod-php
splash/sonata-admin
splash/metadata
splash/openapi
splash/scopes
splash/toolkit
testo/output-teamcity
testo/bridge-symfony
spatie/flare-daemon-runtime