Be part of JetBrains PHPverse 2026 on June 9 – a free online event bringing PHP devs worldwide together.

jbreuer95's avatar

Envoyer + Forge + Loadbalancer, multiple sites with workers "tutorial"

this is completely unnecessary please ignore, #fail

Intro


Today is started using queues and ran into a problem with my current setup. 
I managed to fix it and thought i share my solution with the community. 
 In case someone else runs into this and to see if there might be a better solution. 
 First of all please excuse my english it is not my native language.



Setup

Forge
  • 4 servers, 1 loadbalancer, 3 webservers

  • 3 website, dev.site.com, test.site.com, site.com

  • 12 sites in forge, 1 per website per server

AWS

  • Aurora RDS

  • Elasticcache redis server

  • Alot of other services

Envoyer

  • 3 projects, one per site


  • The projects are completly seperated, diffrent redisDB, Mysql DB etc

The problem


So i have this job that needs to be dispachted on the queue


dispatch(new UpdateFriends($user));

So i created a redis worker with the default queue on the first webserver but then i ran into
the following problem:


ReflectionException: Method __PHP_Incomplete_Class::handle() does not exist in /home/forge/dev.site.com/releases/20161219140033/vendor/laravel/framework/src/Illuminate/Container/Container.php:553


Because the job was dispachted randomly on webserver-3 and the worker was on webserver-1 
the `releases/201612191400 folder didn't exist.



So i needed a worker on every server that only processes jobs that originated from that server.



Solution


To fix this problem i did the following:



i added this line to config/app.php:

'machine' => gethostname(),



So now the application knows on wich server it is.



Then in config/queue.php i did this: 


'redis' => [
            'driver' => 'redis',
            'connection' => 'default',
            'queue' => config('app.machine'),
            'retry_after' => 90,
        ],

So now when you dispatch a job it will dispatch it to a queue with the name of the machine i originated from.



Then in forge i created 9 workers. 1 for every website for every server with the following settings:


Connection: redis

Queue: webserver-1/2/3 (name of server this site is on)

Maximum Seconds Per Job: 60

Rest Seconds When Empty: 10

Maximum Tries: 3

Environment: production/staging/development (value of app_env this site is on)
Run Worker As Daemon: yes (This is a MUST!)  



You need to run the worker as a deamon or else the next step wont work.

Because workers are long running processes you need te restart them after a code change or they won't pick it up.

In envoyer add the following Development hook on all the servers on all sites, i did it after activate release but it should be fine after the git pull.

Name: Restart workers
Run As: forge
Script: cd {{release}}
        php artisan queue:restart
On Servers: All

With this setup a worker on a webserver will only process the jobs that originated from that server and also receive code changes

You can now have working queues for multiple sites behind a loadbalancer with envoyer + forge

Final thoughts


I think this solution is relatively easy to implement.

Also when i need to add a server i only have to add 3 queues in forge en change 3 hooks in envoyer, that can be
done within a minute.


But if anyone has a better solution i would love to hear it. 
 Please keep in mind that i learned about queues only a few hours ago so this might all be completely unnessary :)

0 likes
0 replies

Please or to participate in this conversation.