Thanks to visit codestin.com
Credit goes to github.com

Skip to content

[FEATURE] Criar Extensão RoadRunner Runtime para PivotPHP #4

@CAFernandes

Description

@CAFernandes

📋 Descrição

Desenvolver extensão para integrar PivotPHP com RoadRunner, um application server de alta performance escrito em Go. Esta implementação oferecerá recursos enterprise-grade como workers supervisionados, plugins extensíveis e integração com ecossistema Go.

🎯 Objetivo

Implementar um runtime RoadRunner que oferece:

  • Workers PHP supervisionados pelo Go
  • Sistema de plugins (jobs, KV, broadcast, metrics)
  • Balanceamento de carga inteligente
  • Health checks e circuit breakers
  • Integração com ferramentas DevOps

📦 Entregáveis

1. Novo Repositório

  • Nome: pivotphp-runtime-roadrunner
  • Namespace: Pivot\Runtime\RoadRunner
  • Integração: spiral/roadrunner-php

2. Componentes Principais

RoadRunnerAdapter.php

namespace Pivot\Runtime\RoadRunner;

use Spiral\RoadRunner\Worker;
use Spiral\RoadRunner\Http\PSR7Worker;
use Pivot\Core\Application;
use Nyholm\Psr7\Factory\Psr17Factory;

class RoadRunnerAdapter implements RuntimeAdapterInterface
{
    private PSR7Worker $worker;
    private Application $app;
    private WorkerManager $manager;
    
    public function serve(Application $app, array $config = []): void
    {
        $this->app = $app;
        $this->initializeWorker();
        $this->runWorkerLoop();
    }
    
    private function initializeWorker(): void
    {
        $worker = Worker::create();
        $factory = new Psr17Factory();
        
        $this->worker = new PSR7Worker($worker, $factory, $factory, $factory);
        $this->manager = new WorkerManager($worker);
    }
    
    private function runWorkerLoop(): void
    {
        while ($request = $this->worker->waitRequest()) {
            try {
                // Reset application state
                $this->manager->beforeRequest();
                
                // Process request
                $response = $this->processRequest($request);
                
                // Send response
                $this->worker->respond($response);
                
                // Cleanup
                $this->manager->afterRequest();
                
                // Check if worker should restart
                if ($this->manager->shouldRestart()) {
                    break;
                }
            } catch (\Throwable $e) {
                $this->worker->getWorker()->error((string)$e);
            }
        }
    }
}

WorkerManager.php

namespace Pivot\Runtime\RoadRunner\Worker;

class WorkerManager
{
    private int $requestCount = 0;
    private float $startTime;
    private array $metrics = [];
    
    public function beforeRequest(): void
    {
        $this->requestCount++;
        $this->captureMemoryUsage();
        $this->resetGlobalState();
    }
    
    public function afterRequest(): void
    {
        $this->collectGarbage();
        $this->checkMemoryLimits();
        $this->updateMetrics();
    }
    
    public function shouldRestart(): bool
    {
        // Restart after X requests
        if ($this->requestCount >= config('roadrunner.max_requests', 10000)) {
            return true;
        }
        
        // Restart on memory threshold
        if (memory_get_usage(true) > config('roadrunner.memory_limit', 128 * 1024 * 1024)) {
            return true;
        }
        
        // Restart after TTL
        if (time() - $this->startTime > config('roadrunner.ttl', 3600)) {
            return true;
        }
        
        return false;
    }
}

3. Plugin Integrations

Jobs Plugin

namespace Pivot\Runtime\RoadRunner\Plugins;

use Spiral\RoadRunner\Jobs\JobsInterface;
use Spiral\RoadRunner\Jobs\Queue;

class JobsPlugin
{
    private JobsInterface $jobs;
    
    public function dispatch(string $queue, array $payload): string
    {
        $queue = $this->jobs->connect($queue);
        
        $task = $queue->create(
            class: PivotJobHandler::class,
            payload: $payload,
            options: [
                'delay' => 0,
                'priority' => 10,
            ]
        );
        
        return $queue->dispatch($task);
    }
    
    public function consume(string $queue, callable $handler): void
    {
        $consumer = $this->jobs->consume($queue);
        
        while ($task = $consumer->waitTask()) {
            try {
                $result = $handler($task->payload);
                $task->complete($result);
            } catch (\Throwable $e) {
                $task->fail($e);
            }
        }
    }
}

KV (Key-Value) Plugin

namespace Pivot\Runtime\RoadRunner\Plugins;

use Spiral\RoadRunner\KeyValue\StorageInterface;

class KVPlugin
{
    private StorageInterface $storage;
    
    public function set(string $key, mixed $value, int $ttl = 0): void
    {
        $this->storage->set($key, serialize($value), $ttl);
    }
    
    public function get(string $key): mixed
    {
        $value = $this->storage->get($key);
        return $value ? unserialize($value) : null;
    }
    
    public function mget(array $keys): array
    {
        return array_map('unserialize', $this->storage->mGet($keys));
    }
}

4. Configuration

.rr.yaml

version: "3"

server:
  command: "php worker.php"
  env:
    - APP_ENV: production
    - APP_RUNTIME: roadrunner

http:
  address: 0.0.0.0:8080
  pool:
    num_workers: ${RR_HTTP_WORKERS:-4}
    max_jobs: 500
    allocate_timeout: 60s
    destroy_timeout: 60s
  middleware: ["gzip", "headers", "static"]
  uploads:
    forbid: [".php", ".exe", ".bat"]
    max_size: 100MB
  static:
    dir: "public"
    forbid: [".php", ".htaccess"]
    calculate_etag: true
    weak: true
    cache_duration: 10m

jobs:
  pool:
    num_workers: ${RR_JOBS_WORKERS:-2}
    max_jobs: 100
  pipelines:
    emails:
      driver: memory
      priority: 10
    notifications:
      driver: amqp
      queue: pivot_notifications
      exchange: pivot
      
kv:
  local:
    driver: memory
  redis:
    driver: redis
    config:
      addrs:
        - "localhost:6379"

metrics:
  address: 0.0.0.0:2112
  collect:
    app_metric_*: true

reload:
  enabled: true
  interval: 1s
  patterns: [".php"]
  services:
    http:
      recursive: true
      ignore: ["vendor/"]
      patterns: [".php", ".env"]
      dirs: ["app", "config", "routes"]

logs:
  mode: production
  level: info
  output: stdout
  err_output: stderr

📋 Tasks Detalhadas

Setup e Integração

  • Criar repositório e estrutura
  • Integrar spiral/roadrunner packages
  • Setup worker bootstrap file
  • Configurar .rr.yaml template
  • Docker setup com RoadRunner

Core Implementation

  • RoadRunnerAdapter principal
  • PSR-7 bridge otimizado
  • Worker lifecycle management
  • State reset mechanisms
  • Error handling e recovery

Plugins Integration

  • Jobs plugin para queues
  • KV storage abstraction
  • Broadcast/WebSocket plugin
  • Metrics collection
  • Health checks

Performance & Monitoring

  • Prometheus metrics export
  • Memory profiling
  • Request tracing
  • Performance benchmarks
  • Load balancing strategies

Developer Tools

  • RoadRunner CLI wrapper
  • Development mode
  • Debug panel integration
  • Log aggregation
  • Configuration validation

Production Features

  • Graceful shutdown
  • Zero-downtime reload
  • Circuit breakers
  • Rate limiting
  • SSL/TLS support

Testing

  • Unit tests para adapter
  • Integration tests com RR
  • Plugin functionality tests
  • Load tests (30k+ req/s)
  • Stability tests (72h+)

🔧 Comandos CLI

# Desenvolvimento
./vendor/bin/rr serve -c .rr.dev.yaml

# Produção
./vendor/bin/rr serve

# Workers status
./vendor/bin/rr workers

# Reset workers
./vendor/bin/rr reset

# Métricas
curl http://localhost:2112/metrics

📊 Performance Targets

Métrica Target Notes
Throughput 30,000 req/s Com 4 workers
Latência P50 < 2ms Requests simples
Latência P99 < 8ms Com DB queries
Memory/Worker < 50MB Após 10k requests
CPU Usage < 70% Full load
Startup Time < 100ms Per worker

🚀 Features Únicas

1. Supervisão Go

  • Restart automático de workers
  • Health monitoring nativo
  • Resource limits enforcement

2. Plugin Ecosystem

  • Queue system integrado
  • Cache distribuído
  • WebSocket/SSE support
  • Temporal workflow engine

3. DevOps Ready

  • Kubernetes native
  • Prometheus metrics
  • OpenTelemetry tracing
  • JSON structured logs

4. Performance

  • Zero-allocation hot path
  • Lock-free job distribution
  • NUMA-aware scheduling

📚 Dependências

{
    "require": {
        "php": "^8.1",
        "pivotphp/core": "^1.0",
        "spiral/roadrunner": "^2023.3",
        "spiral/roadrunner-http": "^3.0",
        "spiral/roadrunner-jobs": "^4.0",
        "spiral/roadrunner-kv": "^4.0",
        "nyholm/psr7": "^1.8"
    },
    "require-dev": {
        "spiral/roadrunner-cli": "^2.5",
        "phpunit/phpunit": "^10.0"
    }
}

🗓️ Timeline

  • Semana 1-2: Core adapter implementation
  • Semana 3: Worker management
  • Semana 4-5: Plugins integration
  • Semana 6: Production features
  • Semana 7: Testing e optimization
  • Semana 8: Documentation e release

⚠️ Considerações

Complexidade

  • Requer conhecimento de Go para customizações
  • Configuração mais complexa que outras soluções
  • Debugging através de bridge PHP-Go

Vantagens

  • Performance enterprise-grade
  • Ecosistema rico de plugins
  • Suporte comercial disponível
  • Amplamente usado em produção

🏷️ Labels

  • extension
  • runtime
  • roadrunner
  • enterprise
  • high-performance
  • go-integration

Metadata

Metadata

Assignees

Labels

enhancementNew feature or request

Type

No type

Projects

No projects

Milestone

No milestone

Relationships

None yet

Development

No branches or pull requests

Issue actions