Skip to content

crazy-goat/workerman-bundle

Repository files navigation

Workerman runtime for symfony applications

PHP ^8.2 Symfony ^6.4|^7.0 Tests Status

Workerman is a high-performance, asynchronous event-driven PHP framework written in pure PHP.
This bundle provides a Workerman integration in Symfony, allowing you to easily create a http server, scheduler and supervisor all in one place. This bundle allows you to replace a traditional web application stack like php-fpm + nginx + cron + supervisord, all written in pure PHP (no Go, no external binaries). The request handler works in an event loop which means the Symfony kernel and the dependency injection container are preserved between requests, making your application faster with less (or no) code changes.

Contributing

Please see CONTRIBUTING.md for information about branch protection rules and development workflow.

What new in this fork

  • servers.reuse_port - on linux machines u can use kernel load balancer if SO_REUSEPORT is enabled
  • servers.serve_files - set to false to disable serving file. Use this option for RestAPI projects. Default: false
  • By default luzrain/workerman-bundle parse data to psr7 request and then to symfony Request. This workerman-bundle will create symfony request without psr7 it increase performance, but it is still experimental.

Getting started

Install composer packages

composer require crazy-goat/workerman-bundle

Enable the bundle

<?php
// config/bundles.php

return [
    // ...
    \CrazyGoat\WorkermanBundle\WorkermanBundle::class => ['all' => true],
];

Configure the bundle

A minimal configuration might look like this.
For all available options with documentation, see the command output.

$ bin/console config:dump-reference workerman
# config/packages/workerman.yaml

workerman:
  servers:
    - name: 'Symfony webserver'
      listen: http://0.0.0.0:80
      processes: 4

  reload_strategy:
    exception:
      active: true

    file_monitor:
      active: true

Start application

Using the Symfony console command:

$ bin/console workerman:server start
$ bin/console workerman:server start -d   # daemon mode

Or using the runtime directly:

$ APP_RUNTIME=CrazyGoat\\WorkermanBundle\\Runtime php public/index.php start

Manage the server

$ bin/console workerman:server stop        # stop the server
$ bin/console workerman:server stop -g     # graceful stop
$ bin/console workerman:server restart     # restart
$ bin/console workerman:server restart -d  # restart in daemon mode
$ bin/console workerman:server reload      # reload workers (hot reload)
$ bin/console workerman:server reload -g   # graceful reload
$ bin/console workerman:server status      # show server status
$ bin/console workerman:server connections # show active connections

* For better performance, Workerman recommends installing the php-event extension.

Note: If you have the grpc PHP extension installed, you must set the environment variable GRPC_ENABLE_FORK_SUPPORT=1 before starting the server. The grpc extension spawns background threads that deadlock in forked child processes (e.g. scheduler tasks) unless fork support is explicitly enabled. See grpc/grpc#31241 for details.

Reload strategies

Because of the asynchronous nature of the server, the workers reuse loaded resources on each request. This means that in some cases we need to restart workers.
For example, after an exception is thrown, to prevent services from being in an unrecoverable state. Or every time you change the code in the IDE.
There are a few restart strategies that are implemented and can be enabled or disabled depending on the environment.

  • exception
    Reload worker each time that an exception is thrown during the request handling.
  • max_requests
    Reload worker on every N request to prevent memory leaks.
  • file_monitor
    Reload all workers each time you change the files**.
  • always
    Reload worker after each request.

** It is highly recommended to install the php-inotify extension for file monitoring. Without it, monitoring will work in polling mode, which can be very cpu and disk intensive for large projects.

See all available options for each strategy in the command output.

$ bin/console config:dump-reference workerman reload_strategy

Implement your own reload strategies

You can create reload strategy with your own logic by implementing the RebootStrategyInterface and adding the workerman.reboot_strategy tag to the service.

<?php

use CrazyGoat\WorkermanBundle\Reboot\RebootStrategyInterface;
use Symfony\Component\DependencyInjection\Attribute\AutoconfigureTag;

#[AutoconfigureTag('workerman.reboot_strategy')]
final class TestRebootStrategy implements RebootStrategyInterface
{
    public function shouldReboot(): bool
    {
        return true;
    }
}

Scheduler

Periodic tasks can be configured with attributes or with tags in configuration files.
Schedule string can be formatted in several ways:

  • An integer to define the frequency as a number of seconds. Example: 60
  • An ISO8601 datetime format. Example: 2023-08-01T01:00:00+08:00
  • An ISO8601 duration format. Example: PT1M
  • A relative date format as supported by DateInterval. Example: 1 minutes
  • A cron expression**. Example: */1 * * * *

** Note that you need to install the dragonmantank/cron-expression package if you want to use cron expressions as schedule strings

<?php

use CrazyGoat\WorkermanBundle\Attribute\AsTask;

/**
 * Attribute parameters
 * name: Task name
 * schedule: Task schedule in any format
 * method: method to call, __invoke by default
 * jitter: Maximum jitter in seconds that adds a random time offset to the schedule. Use to prevent multiple tasks from running at the same time
 */
#[AsTask(name: 'My scheduled task', schedule: '1 minutes')]
final class TaskService
{
    public function __invoke()
    {
        // ...
    }
}

Supervisor

Supervisor can be configured with attributes or with tags in configuration files.
Processes are kept alive and wake up if one of them dies.

<?php

use CrazyGoat\WorkermanBundle\Attribute\AsProcess;

/**
 * Attribute parameters
 * name: Process name
 * processes: number of processes
 * method: method to call, __invoke by default
 */
#[AsProcess(name: 'My worker', processes: 1)]
final class ProcessService
{
    public function __invoke()
    {
        // ...
    }
}

About

Symfony bundle for Workerman — async HTTP server, scheduler, and supervisor replacing php-fpm + nginx + cron + supervisord in pure PHP

Topics

Resources

License

Contributing

Stars

Watchers

Forks

Packages

 
 
 

Contributors

Languages