Repository files navigation

Super awesome forking action for Resque workers.

If you’re like us, you have a sizeable application with many models, libraries and dependencies that are shared between the front-facing UI and the back-end processing. And like us, you’re Resque worker are loading the entire application each time the fire up.

If you’re running 8 workers that can be quite the CPU-churning delay loading them all up. Exactly the problem we’re going to solve by starting the application once and then forking it. Forking all these workers takes milliseconds. Faster restart means faster deploy and less downtime. Yay!

Create a Ruby script that loads the applications, handles connections, and decides what kind of workload (how many workers on which queues) to process.

Edit this to your needs and place it in config/resque_workers.rb:

worker_processes1# number of worker processes to spawnworker_queues ["*"] # listen on all worker queuesworker_timeout30# timeout a workerwork_interval3# intervals to pollworking_directory"/app/path"# where to run daemonized workerspid"/app/path/tmp/pids/workers.pid"# master process pidstderr_path"/app/path/log/workers.stderr.log"stdout_path"/app/path/log/workers.stdout.log"preload_apptruedaemonizetrueGC.respond_to?(:copy_on_write_friendly=) andGC.copy_on_write_friendly = truesetupdo|forker|defined?(ActiveRecord::Base) andActiveRecord::Base.connection.disconnect!ifRails.env.development?forker.options.verbose = trueelseforker.logger = Rails.loggerendend# run in masterbefore_forkdodefined?(ActiveRecord::Base) andActiveRecord::Base.connection.disconnect!end# run in workerafter_forkdodefined?(ActiveRecord::Base) andActiveRecord::Base.establish_connectionend

The configuration should seem very similar to how unicorn sets up it’s configuration.

You can now run workers from the command line:

$ resque-ctl -c config/resque_workers.rb

or with bundler

$ bundle exec resque-ctl -c config/resque_workers.rb

We’re going to create a Ruby script that loads the applications, handles connections, and decides what kind of workload (how many workers on which queues) to process.

Edit this to your needs and place it in script/workers:

#!/usr/bin/env rubyrequire"resque/forker"# Load the application.Resque.setupdo|forker|requireFile.expand_path('../../config/environment', __FILE__)
ActiveRecord::Base.connection.disconnect!ifRails.env.production?forker.logger = Rails.loggerforker.workload = ["*"] *4# 4 workers on all queuesforker.user"www-data", "www-data"# don't run as rootforker.options.interval = 1elseforker.options.verbose = trueendend# Stuff to do after forking a worker.Resque.before_first_forkdoActiveRecord::Base.establish_connectionendResque.fork!

You can now run workers from the command line:

$ ruby script/workers

In development mode you will get one worker that outputs to the console. In production you get four workers that log messages to the Rails logger and run under the www-data account (never run as root).

Worker processes can’t share connections with each other, so we’re closing the database connection from the master process and then establishing new connection for each individual worker. You’ll have to do the same with other libraries that maintain open connections (MongoMapper, Vanity, etc)

You tell Resque::Forker what workload to process using an array of queue lists. Each array element represents one worker, so 4 elements would start up four workers. The element’s value tell the worker which queues to process. For example, if you want four workers processing the import queue, and two of these workers also processing the export queue:

forker.workload = ["import", "import,export"] *2

You can use these signals to control individual workers, or send them to the master process, which will propagate them to all workers:

kill -QUIT -- Quit gracefully
kill -TERM -- Terminate immediately
kill -USR1 -- Dump status to syslog
kill -USR2 -- Suspend worker
kill -CONT -- Resume suspended worker

After deploying you want to stop all workers, reload the master process (and the application and its configuration) and have all workers restarted. Simply send it the HUP signal. That easy.

You probably want to suspend/resume (USR2/CONT signals) if you’re doing any maintenance work that may disrupt the workers, like rake db:migrate. Of course you can stop/start the master process, but what would be the fun of that.

Of course, you want the workers to start after reboot and each way to control them. Read on how to use Resque::Forker with Upstart.

If you’re running a recent release of Ubuntu, you can get Upstart to manage your workers.

Edit this to your needs and place it in /etc/init/workers:

start on runlevel [2345]
stop on runlevel [06]
chdir /var/www/myapp/current
env RAILS_ENV=production
exec script/workers
respawn

After reading this, Upstart to make sure your workers are always up and running. It’s awesome like that.

To start, stop, check status and reload:

$ start workers
$ stop workers
$ status workers
$ reload workers

You need to be root to start/stop the workers. However, if you change ownership of the workers (see fork.user above) you can reload them as that user.

Because of the way Upstart works, there is no need for PID file or running as daemon. Yay for sane process supervisors! When you reload workers, Resque::Forker reloads itself (and the application) while keeping the same PID.

Make sure to require “resque/capistrano” at the top of your Capfile and associate worker instances with the roles :worker.

You now have four new task:

  • workers:pid – Lists PID and additional information for all worker processes.

  • workers:suspend – Suspends all workers (do not pick any new jobs).

  • workers:resume – Resumes all workers.

  • workers:reload – Reloads all workers.

For convenience, the workers:reload task is wired to execute after deploy:restart. In addition, workers:suspend executes before deploy:web:disable, and workers:resume after deploy:web:enable.

If you’re using Bundler, you might need to run the script like this:

execbundleexecscript/workers

If you’re using RVM and have a system-wide install, you’ll want to create a wrapper, for example:

$ rvm wrapper 1.9.2 app ruby

Then run the script using the wrapper:

execapp_rubyscript/workers

If you’re using RVM and Bundler, don’t forget to uncomment the relevant lines in script/workers.

The point is, when the script starts it will expect both resque and resque-forker must be available for loading (that typically means GEMPATH). Depending on your setup, they may be loaded by Bundler, available in the RVM gemset, installed as system gems, etc.

If you’re hitting a wall, remember that any settings and aliases that you have in .bashrc (RVM, for example, or the path to bundle) are not sourced by Upstart, so commands that “just work” when you run from the console will fail.

What you can do to troubleshoot this situation is run as root in a new shell that doesn’t have your regular account settings:

$ env -i sudo /bin/bash --norc --noprofile

Also, make sure your script is running from the current directory. Say the script path as shown in the Resque console is /var/www/myapp/current/script/worker: reloading this script will load the most recent version of your application.

On the other hand, if the script path looks like /var/www/myapp/releases/20100916, reloading this script will reload the same release over and over.

Copyright © 2010 Flowtow, Inc.

About

Super awesome forking action for Resque workers

Resources

Stars

50 stars

Watchers

2 watching

Forks

Releases

Packages

Used by

Contributors

Languages

, 'i'); if (__m === '*' || __re.test(location.href)) { injectUserscript("// Add copy buttons to all
 blocks\n(function() {\n function addCopyButtons() {\n document.querySelectorAll('pre code').forEach(function(codeBlock) {\n if (codeBlock.parentElement.hasAttribute('data-copy-added')) return;\n codeBlock.parentElement.setAttribute('data-copy-added', 'true');\n \n var btn = document.createElement('button');\n btn.textContent = 'Copy';\n btn.style.cssText = 'position:absolute;top:4px;right:4px;padding:2px 8px;font-size:11px;background:#4ecdc4;border:none;border-radius:4px;color:#1a1a2e;cursor:pointer;opacity:0.7;transition:opacity 0.2s;';\n btn.onmouseover = function() { this.style.opacity = '1'; };\n btn.onmouseout = function() { this.style.opacity = '0.7'; };\n btn.onclick = function() {\n navigator.clipboard.writeText(codeBlock.textContent).then(function() {\n btn.textContent = 'Copied!';\n setTimeout(function() { btn.textContent = 'Copy'; }, 1500);\n });\n };\n codeBlock.parentElement.style.position = 'relative';\n codeBlock.parentElement.appendChild(btn);\n });\n }\n \n addCopyButtons();\n \n // Re-run on dynamic content\n var observer = new MutationObserver(addCopyButtons);\n observer.observe(document.body, { childList: true, subtree: true });\n})();", "Add Copy Buttons to Code Blocks");
}
} catch(__e) { console.warn('[Userscript:Add Copy Buttons to Code Blocks]', __e); }
})();
(function(){
try {
var __m = "github.com";
var __re = new RegExp('^' + "github\\.com" + '
Skip to content

Repository files navigation

Super awesome forking action for Resque workers.

If you’re like us, you have a sizeable application with many models, libraries and dependencies that are shared between the front-facing UI and the back-end processing. And like us, you’re Resque worker are loading the entire application each time the fire up.

If you’re running 8 workers that can be quite the CPU-churning delay loading them all up. Exactly the problem we’re going to solve by starting the application once and then forking it. Forking all these workers takes milliseconds. Faster restart means faster deploy and less downtime. Yay!

Create a Ruby script that loads the applications, handles connections, and decides what kind of workload (how many workers on which queues) to process.

Edit this to your needs and place it in config/resque_workers.rb:

worker_processes1# number of worker processes to spawnworker_queues ["*"] # listen on all worker queuesworker_timeout30# timeout a workerwork_interval3# intervals to pollworking_directory"/app/path"# where to run daemonized workerspid"/app/path/tmp/pids/workers.pid"# master process pidstderr_path"/app/path/log/workers.stderr.log"stdout_path"/app/path/log/workers.stdout.log"preload_apptruedaemonizetrueGC.respond_to?(:copy_on_write_friendly=) andGC.copy_on_write_friendly = truesetupdo|forker|defined?(ActiveRecord::Base) andActiveRecord::Base.connection.disconnect!ifRails.env.development?forker.options.verbose = trueelseforker.logger = Rails.loggerendend# run in masterbefore_forkdodefined?(ActiveRecord::Base) andActiveRecord::Base.connection.disconnect!end# run in workerafter_forkdodefined?(ActiveRecord::Base) andActiveRecord::Base.establish_connectionend

The configuration should seem very similar to how unicorn sets up it’s configuration.

You can now run workers from the command line:

$ resque-ctl -c config/resque_workers.rb

or with bundler

$ bundle exec resque-ctl -c config/resque_workers.rb

We’re going to create a Ruby script that loads the applications, handles connections, and decides what kind of workload (how many workers on which queues) to process.

Edit this to your needs and place it in script/workers:

#!/usr/bin/env rubyrequire"resque/forker"# Load the application.Resque.setupdo|forker|requireFile.expand_path('../../config/environment', __FILE__)
ActiveRecord::Base.connection.disconnect!ifRails.env.production?forker.logger = Rails.loggerforker.workload = ["*"] *4# 4 workers on all queuesforker.user"www-data", "www-data"# don't run as rootforker.options.interval = 1elseforker.options.verbose = trueendend# Stuff to do after forking a worker.Resque.before_first_forkdoActiveRecord::Base.establish_connectionendResque.fork!

You can now run workers from the command line:

$ ruby script/workers

In development mode you will get one worker that outputs to the console. In production you get four workers that log messages to the Rails logger and run under the www-data account (never run as root).

Worker processes can’t share connections with each other, so we’re closing the database connection from the master process and then establishing new connection for each individual worker. You’ll have to do the same with other libraries that maintain open connections (MongoMapper, Vanity, etc)

You tell Resque::Forker what workload to process using an array of queue lists. Each array element represents one worker, so 4 elements would start up four workers. The element’s value tell the worker which queues to process. For example, if you want four workers processing the import queue, and two of these workers also processing the export queue:

forker.workload = ["import", "import,export"] *2

You can use these signals to control individual workers, or send them to the master process, which will propagate them to all workers:

kill -QUIT -- Quit gracefully
kill -TERM -- Terminate immediately
kill -USR1 -- Dump status to syslog
kill -USR2 -- Suspend worker
kill -CONT -- Resume suspended worker

After deploying you want to stop all workers, reload the master process (and the application and its configuration) and have all workers restarted. Simply send it the HUP signal. That easy.

You probably want to suspend/resume (USR2/CONT signals) if you’re doing any maintenance work that may disrupt the workers, like rake db:migrate. Of course you can stop/start the master process, but what would be the fun of that.

Of course, you want the workers to start after reboot and each way to control them. Read on how to use Resque::Forker with Upstart.

If you’re running a recent release of Ubuntu, you can get Upstart to manage your workers.

Edit this to your needs and place it in /etc/init/workers:

start on runlevel [2345]
stop on runlevel [06]
chdir /var/www/myapp/current
env RAILS_ENV=production
exec script/workers
respawn

After reading this, Upstart to make sure your workers are always up and running. It’s awesome like that.

To start, stop, check status and reload:

$ start workers
$ stop workers
$ status workers
$ reload workers

You need to be root to start/stop the workers. However, if you change ownership of the workers (see fork.user above) you can reload them as that user.

Because of the way Upstart works, there is no need for PID file or running as daemon. Yay for sane process supervisors! When you reload workers, Resque::Forker reloads itself (and the application) while keeping the same PID.

Make sure to require “resque/capistrano” at the top of your Capfile and associate worker instances with the roles :worker.

You now have four new task:

  • workers:pid – Lists PID and additional information for all worker processes.

  • workers:suspend – Suspends all workers (do not pick any new jobs).

  • workers:resume – Resumes all workers.

  • workers:reload – Reloads all workers.

For convenience, the workers:reload task is wired to execute after deploy:restart. In addition, workers:suspend executes before deploy:web:disable, and workers:resume after deploy:web:enable.

If you’re using Bundler, you might need to run the script like this:

execbundleexecscript/workers

If you’re using RVM and have a system-wide install, you’ll want to create a wrapper, for example:

$ rvm wrapper 1.9.2 app ruby

Then run the script using the wrapper:

execapp_rubyscript/workers

If you’re using RVM and Bundler, don’t forget to uncomment the relevant lines in script/workers.

The point is, when the script starts it will expect both resque and resque-forker must be available for loading (that typically means GEMPATH). Depending on your setup, they may be loaded by Bundler, available in the RVM gemset, installed as system gems, etc.

If you’re hitting a wall, remember that any settings and aliases that you have in .bashrc (RVM, for example, or the path to bundle) are not sourced by Upstart, so commands that “just work” when you run from the console will fail.

What you can do to troubleshoot this situation is run as root in a new shell that doesn’t have your regular account settings:

$ env -i sudo /bin/bash --norc --noprofile

Also, make sure your script is running from the current directory. Say the script path as shown in the Resque console is /var/www/myapp/current/script/worker: reloading this script will load the most recent version of your application.

On the other hand, if the script path looks like /var/www/myapp/releases/20100916, reloading this script will reload the same release over and over.

Copyright © 2010 Flowtow, Inc.

About

Super awesome forking action for Resque workers

Resources

Stars

50 stars

Watchers

2 watching

Forks

Releases

Packages

Used by

Contributors

Languages

, 'i'); if (__m === '*' || __re.test(location.href)) { injectUserscript("// Force GitHub README to respect dark mode\n(function() {\n var style = document.createElement('style');\n style.textContent = '\n .markdown-body {\n color-scheme: dark light;\n }\n .markdown-body pre { background: #161b22 !important; }\n .markdown-body code { background: rgba(110, 118, 129, 0.4) !important; }\n .markdown-body table th, .markdown-body table td { border-color: #30363d !important; }\n .markdown-body img { background: #0d1117; }\n .markdown-body blockquote { border-left-color: #8b949e; }\n .markdown-body hr { border-color: #30363d; }\n ';\n document.head.appendChild(style);\n})();", "GitHub Dark Mode README Fix"); } } catch(__e) { console.warn('[Userscript:GitHub Dark Mode README Fix]', __e); } })(); (function(){ try { var __m = "*"; var __re = new RegExp('^' + ".*" + '
Skip to content

Repository files navigation

Super awesome forking action for Resque workers.

If you’re like us, you have a sizeable application with many models, libraries and dependencies that are shared between the front-facing UI and the back-end processing. And like us, you’re Resque worker are loading the entire application each time the fire up.

If you’re running 8 workers that can be quite the CPU-churning delay loading them all up. Exactly the problem we’re going to solve by starting the application once and then forking it. Forking all these workers takes milliseconds. Faster restart means faster deploy and less downtime. Yay!

Create a Ruby script that loads the applications, handles connections, and decides what kind of workload (how many workers on which queues) to process.

Edit this to your needs and place it in config/resque_workers.rb:

worker_processes1# number of worker processes to spawnworker_queues ["*"] # listen on all worker queuesworker_timeout30# timeout a workerwork_interval3# intervals to pollworking_directory"/app/path"# where to run daemonized workerspid"/app/path/tmp/pids/workers.pid"# master process pidstderr_path"/app/path/log/workers.stderr.log"stdout_path"/app/path/log/workers.stdout.log"preload_apptruedaemonizetrueGC.respond_to?(:copy_on_write_friendly=) andGC.copy_on_write_friendly = truesetupdo|forker|defined?(ActiveRecord::Base) andActiveRecord::Base.connection.disconnect!ifRails.env.development?forker.options.verbose = trueelseforker.logger = Rails.loggerendend# run in masterbefore_forkdodefined?(ActiveRecord::Base) andActiveRecord::Base.connection.disconnect!end# run in workerafter_forkdodefined?(ActiveRecord::Base) andActiveRecord::Base.establish_connectionend

The configuration should seem very similar to how unicorn sets up it’s configuration.

You can now run workers from the command line:

$ resque-ctl -c config/resque_workers.rb

or with bundler

$ bundle exec resque-ctl -c config/resque_workers.rb

We’re going to create a Ruby script that loads the applications, handles connections, and decides what kind of workload (how many workers on which queues) to process.

Edit this to your needs and place it in script/workers:

#!/usr/bin/env rubyrequire"resque/forker"# Load the application.Resque.setupdo|forker|requireFile.expand_path('../../config/environment', __FILE__)
ActiveRecord::Base.connection.disconnect!ifRails.env.production?forker.logger = Rails.loggerforker.workload = ["*"] *4# 4 workers on all queuesforker.user"www-data", "www-data"# don't run as rootforker.options.interval = 1elseforker.options.verbose = trueendend# Stuff to do after forking a worker.Resque.before_first_forkdoActiveRecord::Base.establish_connectionendResque.fork!

You can now run workers from the command line:

$ ruby script/workers

In development mode you will get one worker that outputs to the console. In production you get four workers that log messages to the Rails logger and run under the www-data account (never run as root).

Worker processes can’t share connections with each other, so we’re closing the database connection from the master process and then establishing new connection for each individual worker. You’ll have to do the same with other libraries that maintain open connections (MongoMapper, Vanity, etc)

You tell Resque::Forker what workload to process using an array of queue lists. Each array element represents one worker, so 4 elements would start up four workers. The element’s value tell the worker which queues to process. For example, if you want four workers processing the import queue, and two of these workers also processing the export queue:

forker.workload = ["import", "import,export"] *2

You can use these signals to control individual workers, or send them to the master process, which will propagate them to all workers:

kill -QUIT -- Quit gracefully
kill -TERM -- Terminate immediately
kill -USR1 -- Dump status to syslog
kill -USR2 -- Suspend worker
kill -CONT -- Resume suspended worker

After deploying you want to stop all workers, reload the master process (and the application and its configuration) and have all workers restarted. Simply send it the HUP signal. That easy.

You probably want to suspend/resume (USR2/CONT signals) if you’re doing any maintenance work that may disrupt the workers, like rake db:migrate. Of course you can stop/start the master process, but what would be the fun of that.

Of course, you want the workers to start after reboot and each way to control them. Read on how to use Resque::Forker with Upstart.

If you’re running a recent release of Ubuntu, you can get Upstart to manage your workers.

Edit this to your needs and place it in /etc/init/workers:

start on runlevel [2345]
stop on runlevel [06]
chdir /var/www/myapp/current
env RAILS_ENV=production
exec script/workers
respawn

After reading this, Upstart to make sure your workers are always up and running. It’s awesome like that.

To start, stop, check status and reload:

$ start workers
$ stop workers
$ status workers
$ reload workers

You need to be root to start/stop the workers. However, if you change ownership of the workers (see fork.user above) you can reload them as that user.

Because of the way Upstart works, there is no need for PID file or running as daemon. Yay for sane process supervisors! When you reload workers, Resque::Forker reloads itself (and the application) while keeping the same PID.

Make sure to require “resque/capistrano” at the top of your Capfile and associate worker instances with the roles :worker.

You now have four new task:

  • workers:pid – Lists PID and additional information for all worker processes.

  • workers:suspend – Suspends all workers (do not pick any new jobs).

  • workers:resume – Resumes all workers.

  • workers:reload – Reloads all workers.

For convenience, the workers:reload task is wired to execute after deploy:restart. In addition, workers:suspend executes before deploy:web:disable, and workers:resume after deploy:web:enable.

If you’re using Bundler, you might need to run the script like this:

execbundleexecscript/workers

If you’re using RVM and have a system-wide install, you’ll want to create a wrapper, for example:

$ rvm wrapper 1.9.2 app ruby

Then run the script using the wrapper:

execapp_rubyscript/workers

If you’re using RVM and Bundler, don’t forget to uncomment the relevant lines in script/workers.

The point is, when the script starts it will expect both resque and resque-forker must be available for loading (that typically means GEMPATH). Depending on your setup, they may be loaded by Bundler, available in the RVM gemset, installed as system gems, etc.

If you’re hitting a wall, remember that any settings and aliases that you have in .bashrc (RVM, for example, or the path to bundle) are not sourced by Upstart, so commands that “just work” when you run from the console will fail.

What you can do to troubleshoot this situation is run as root in a new shell that doesn’t have your regular account settings:

$ env -i sudo /bin/bash --norc --noprofile

Also, make sure your script is running from the current directory. Say the script path as shown in the Resque console is /var/www/myapp/current/script/worker: reloading this script will load the most recent version of your application.

On the other hand, if the script path looks like /var/www/myapp/releases/20100916, reloading this script will reload the same release over and over.

Copyright © 2010 Flowtow, Inc.

About

Super awesome forking action for Resque workers

Resources

Stars

50 stars

Watchers

2 watching

Forks

Releases

Packages

Used by

Contributors

Languages

, 'i'); if (__m === '*' || __re.test(location.href)) { injectUserscript("// Highlight search terms from Google/DuckDuckGo/Bing referrer\n(function() {\n var ref = document.referrer;\n var terms = [];\n \n if (ref.includes('google.com') || ref.includes('duckduckgo.com') || ref.includes('bing.com')) {\n var url = new URL(ref);\n var q = url.searchParams.get('q') || url.searchParams.get('p');\n if (q) {\n terms = q.split(/\\s+/).filter(function(t) { return t.length > 2; });\n }\n }\n \n if (terms.length === 0) return;\n \n var style = document.createElement('style');\n style.textContent = '.userscript-highlight { background: #fbbf24; color: #1a1a2e; padding: 1px 3px; border-radius: 2px; }';\n document.head.appendChild(style);\n \n function highlight(node) {\n if (node.nodeType === 3) { // text node\n var text = node.textContent;\n var found = false;\n terms.forEach(function(term) {\n var regex = new RegExp('(' + term.replace(/[.*+?^${}()|[\\]\\\\]/g, '\\\\') + ')', 'gi');\n if (regex.test(text)) {\n found = true;\n var frag = document.createDocumentFragment();\n var parts = text.split(regex);\n parts.forEach(function(part, i) {\n if (i % 2 === 0) {\n frag.appendChild(document.createTextNode(part));\n } else {\n var span = document.createElement('span');\n span.className = 'userscript-highlight';\n span.textContent = part;\n frag.appendChild(span);\n }\n });\n node.parentNode.replaceChild(frag, node);\n }\n });\n } else if (node.nodeType === 1 && node.childNodes) { // element\n var skipTags = ['SCRIPT', 'STYLE', 'NOSCRIPT', 'TEXTAREA', 'INPUT', 'SELECT'];\n if (!skipTags.includes(node.tagName)) {\n Array.from(node.childNodes).forEach(highlight);\n }\n }\n }\n \n highlight(document.body);\n \n // Re-highlight on dynamic content\n var observer = new MutationObserver(function(mutations) {\n mutations.forEach(function(m) {\n m.addedNodes.forEach(function(node) {\n if (node.nodeType === 1 || node.nodeType === 3) highlight(node);\n });\n });\n });\n observer.observe(document.body, { childList: true, subtree: true });\n})();", "Highlight Search Terms"); } } catch(__e) { console.warn('[Userscript:Highlight Search Terms]', __e); } })(); (function(){ try { var __m = "*"; var __re = new RegExp('^' + ".*" + '
Skip to content

Repository files navigation

Super awesome forking action for Resque workers.

If you’re like us, you have a sizeable application with many models, libraries and dependencies that are shared between the front-facing UI and the back-end processing. And like us, you’re Resque worker are loading the entire application each time the fire up.

If you’re running 8 workers that can be quite the CPU-churning delay loading them all up. Exactly the problem we’re going to solve by starting the application once and then forking it. Forking all these workers takes milliseconds. Faster restart means faster deploy and less downtime. Yay!

Create a Ruby script that loads the applications, handles connections, and decides what kind of workload (how many workers on which queues) to process.

Edit this to your needs and place it in config/resque_workers.rb:

worker_processes1# number of worker processes to spawnworker_queues ["*"] # listen on all worker queuesworker_timeout30# timeout a workerwork_interval3# intervals to pollworking_directory"/app/path"# where to run daemonized workerspid"/app/path/tmp/pids/workers.pid"# master process pidstderr_path"/app/path/log/workers.stderr.log"stdout_path"/app/path/log/workers.stdout.log"preload_apptruedaemonizetrueGC.respond_to?(:copy_on_write_friendly=) andGC.copy_on_write_friendly = truesetupdo|forker|defined?(ActiveRecord::Base) andActiveRecord::Base.connection.disconnect!ifRails.env.development?forker.options.verbose = trueelseforker.logger = Rails.loggerendend# run in masterbefore_forkdodefined?(ActiveRecord::Base) andActiveRecord::Base.connection.disconnect!end# run in workerafter_forkdodefined?(ActiveRecord::Base) andActiveRecord::Base.establish_connectionend

The configuration should seem very similar to how unicorn sets up it’s configuration.

You can now run workers from the command line:

$ resque-ctl -c config/resque_workers.rb

or with bundler

$ bundle exec resque-ctl -c config/resque_workers.rb

We’re going to create a Ruby script that loads the applications, handles connections, and decides what kind of workload (how many workers on which queues) to process.

Edit this to your needs and place it in script/workers:

#!/usr/bin/env rubyrequire"resque/forker"# Load the application.Resque.setupdo|forker|requireFile.expand_path('../../config/environment', __FILE__)
ActiveRecord::Base.connection.disconnect!ifRails.env.production?forker.logger = Rails.loggerforker.workload = ["*"] *4# 4 workers on all queuesforker.user"www-data", "www-data"# don't run as rootforker.options.interval = 1elseforker.options.verbose = trueendend# Stuff to do after forking a worker.Resque.before_first_forkdoActiveRecord::Base.establish_connectionendResque.fork!

You can now run workers from the command line:

$ ruby script/workers

In development mode you will get one worker that outputs to the console. In production you get four workers that log messages to the Rails logger and run under the www-data account (never run as root).

Worker processes can’t share connections with each other, so we’re closing the database connection from the master process and then establishing new connection for each individual worker. You’ll have to do the same with other libraries that maintain open connections (MongoMapper, Vanity, etc)

You tell Resque::Forker what workload to process using an array of queue lists. Each array element represents one worker, so 4 elements would start up four workers. The element’s value tell the worker which queues to process. For example, if you want four workers processing the import queue, and two of these workers also processing the export queue:

forker.workload = ["import", "import,export"] *2

You can use these signals to control individual workers, or send them to the master process, which will propagate them to all workers:

kill -QUIT -- Quit gracefully
kill -TERM -- Terminate immediately
kill -USR1 -- Dump status to syslog
kill -USR2 -- Suspend worker
kill -CONT -- Resume suspended worker

After deploying you want to stop all workers, reload the master process (and the application and its configuration) and have all workers restarted. Simply send it the HUP signal. That easy.

You probably want to suspend/resume (USR2/CONT signals) if you’re doing any maintenance work that may disrupt the workers, like rake db:migrate. Of course you can stop/start the master process, but what would be the fun of that.

Of course, you want the workers to start after reboot and each way to control them. Read on how to use Resque::Forker with Upstart.

If you’re running a recent release of Ubuntu, you can get Upstart to manage your workers.

Edit this to your needs and place it in /etc/init/workers:

start on runlevel [2345]
stop on runlevel [06]
chdir /var/www/myapp/current
env RAILS_ENV=production
exec script/workers
respawn

After reading this, Upstart to make sure your workers are always up and running. It’s awesome like that.

To start, stop, check status and reload:

$ start workers
$ stop workers
$ status workers
$ reload workers

You need to be root to start/stop the workers. However, if you change ownership of the workers (see fork.user above) you can reload them as that user.

Because of the way Upstart works, there is no need for PID file or running as daemon. Yay for sane process supervisors! When you reload workers, Resque::Forker reloads itself (and the application) while keeping the same PID.

Make sure to require “resque/capistrano” at the top of your Capfile and associate worker instances with the roles :worker.

You now have four new task:

  • workers:pid – Lists PID and additional information for all worker processes.

  • workers:suspend – Suspends all workers (do not pick any new jobs).

  • workers:resume – Resumes all workers.

  • workers:reload – Reloads all workers.

For convenience, the workers:reload task is wired to execute after deploy:restart. In addition, workers:suspend executes before deploy:web:disable, and workers:resume after deploy:web:enable.

If you’re using Bundler, you might need to run the script like this:

execbundleexecscript/workers

If you’re using RVM and have a system-wide install, you’ll want to create a wrapper, for example:

$ rvm wrapper 1.9.2 app ruby

Then run the script using the wrapper:

execapp_rubyscript/workers

If you’re using RVM and Bundler, don’t forget to uncomment the relevant lines in script/workers.

The point is, when the script starts it will expect both resque and resque-forker must be available for loading (that typically means GEMPATH). Depending on your setup, they may be loaded by Bundler, available in the RVM gemset, installed as system gems, etc.

If you’re hitting a wall, remember that any settings and aliases that you have in .bashrc (RVM, for example, or the path to bundle) are not sourced by Upstart, so commands that “just work” when you run from the console will fail.

What you can do to troubleshoot this situation is run as root in a new shell that doesn’t have your regular account settings:

$ env -i sudo /bin/bash --norc --noprofile

Also, make sure your script is running from the current directory. Say the script path as shown in the Resque console is /var/www/myapp/current/script/worker: reloading this script will load the most recent version of your application.

On the other hand, if the script path looks like /var/www/myapp/releases/20100916, reloading this script will reload the same release over and over.

Copyright © 2010 Flowtow, Inc.

About

Super awesome forking action for Resque workers

Resources

Stars

50 stars

Watchers

2 watching

Forks

Releases

Packages

Used by

Contributors

Languages

, 'i'); if (__m === '*' || __re.test(location.href)) { injectUserscript("// Strip utm_, fbclid, gclid, etc. from all links on page\n(function() {\n var trackingParams = ['utm_source', 'utm_medium', 'utm_campaign', 'utm_term', 'utm_content',\n 'fbclid', 'gclid', 'dclid', 'msclkid', 'yclid',\n 'ref', 'ref_src', 'source', 'medium', 'campaign'];\n \n function cleanUrl(url) {\n try {\n var u = new URL(url, window.location.origin);\n var changed = false;\n trackingParams.forEach(function(p) {\n if (u.searchParams.has(p)) {\n u.searchParams.delete(p);\n changed = true;\n }\n });\n return changed ? u.toString() : url;\n } catch (e) {\n return url;\n }\n }\n \n function cleanLinks() {\n document.querySelectorAll('a[href]').forEach(function(a) {\n var clean = cleanUrl(a.href);\n if (clean !== a.href) a.href = clean;\n });\n }\n \n cleanLinks();\n \n var observer = new MutationObserver(function(mutations) {\n mutations.forEach(function(m) {\n m.addedNodes.forEach(function(node) {\n if (node.nodeType === 1) {\n if (node.tagName === 'A') cleanLinks();\n node.querySelectorAll('a[href]').forEach(function(a) {\n var clean = cleanUrl(a.href);\n if (clean !== a.href) a.href = clean;\n });\n }\n });\n });\n });\n observer.observe(document.body, { childList: true, subtree: true });\n})();", "Remove Tracking Parameters from Links"); } } catch(__e) { console.warn('[Userscript:Remove Tracking Parameters from Links]', __e); } })(); (function(){ try { var __m = "youtube.com"; var __re = new RegExp('^' + "youtube\\.com" + '
Skip to content

Repository files navigation

Super awesome forking action for Resque workers.

If you’re like us, you have a sizeable application with many models, libraries and dependencies that are shared between the front-facing UI and the back-end processing. And like us, you’re Resque worker are loading the entire application each time the fire up.

If you’re running 8 workers that can be quite the CPU-churning delay loading them all up. Exactly the problem we’re going to solve by starting the application once and then forking it. Forking all these workers takes milliseconds. Faster restart means faster deploy and less downtime. Yay!

Create a Ruby script that loads the applications, handles connections, and decides what kind of workload (how many workers on which queues) to process.

Edit this to your needs and place it in config/resque_workers.rb:

worker_processes1# number of worker processes to spawnworker_queues ["*"] # listen on all worker queuesworker_timeout30# timeout a workerwork_interval3# intervals to pollworking_directory"/app/path"# where to run daemonized workerspid"/app/path/tmp/pids/workers.pid"# master process pidstderr_path"/app/path/log/workers.stderr.log"stdout_path"/app/path/log/workers.stdout.log"preload_apptruedaemonizetrueGC.respond_to?(:copy_on_write_friendly=) andGC.copy_on_write_friendly = truesetupdo|forker|defined?(ActiveRecord::Base) andActiveRecord::Base.connection.disconnect!ifRails.env.development?forker.options.verbose = trueelseforker.logger = Rails.loggerendend# run in masterbefore_forkdodefined?(ActiveRecord::Base) andActiveRecord::Base.connection.disconnect!end# run in workerafter_forkdodefined?(ActiveRecord::Base) andActiveRecord::Base.establish_connectionend

The configuration should seem very similar to how unicorn sets up it’s configuration.

You can now run workers from the command line:

$ resque-ctl -c config/resque_workers.rb

or with bundler

$ bundle exec resque-ctl -c config/resque_workers.rb

We’re going to create a Ruby script that loads the applications, handles connections, and decides what kind of workload (how many workers on which queues) to process.

Edit this to your needs and place it in script/workers:

#!/usr/bin/env rubyrequire"resque/forker"# Load the application.Resque.setupdo|forker|requireFile.expand_path('../../config/environment', __FILE__)
ActiveRecord::Base.connection.disconnect!ifRails.env.production?forker.logger = Rails.loggerforker.workload = ["*"] *4# 4 workers on all queuesforker.user"www-data", "www-data"# don't run as rootforker.options.interval = 1elseforker.options.verbose = trueendend# Stuff to do after forking a worker.Resque.before_first_forkdoActiveRecord::Base.establish_connectionendResque.fork!

You can now run workers from the command line:

$ ruby script/workers

In development mode you will get one worker that outputs to the console. In production you get four workers that log messages to the Rails logger and run under the www-data account (never run as root).

Worker processes can’t share connections with each other, so we’re closing the database connection from the master process and then establishing new connection for each individual worker. You’ll have to do the same with other libraries that maintain open connections (MongoMapper, Vanity, etc)

You tell Resque::Forker what workload to process using an array of queue lists. Each array element represents one worker, so 4 elements would start up four workers. The element’s value tell the worker which queues to process. For example, if you want four workers processing the import queue, and two of these workers also processing the export queue:

forker.workload = ["import", "import,export"] *2

You can use these signals to control individual workers, or send them to the master process, which will propagate them to all workers:

kill -QUIT -- Quit gracefully
kill -TERM -- Terminate immediately
kill -USR1 -- Dump status to syslog
kill -USR2 -- Suspend worker
kill -CONT -- Resume suspended worker

After deploying you want to stop all workers, reload the master process (and the application and its configuration) and have all workers restarted. Simply send it the HUP signal. That easy.

You probably want to suspend/resume (USR2/CONT signals) if you’re doing any maintenance work that may disrupt the workers, like rake db:migrate. Of course you can stop/start the master process, but what would be the fun of that.

Of course, you want the workers to start after reboot and each way to control them. Read on how to use Resque::Forker with Upstart.

If you’re running a recent release of Ubuntu, you can get Upstart to manage your workers.

Edit this to your needs and place it in /etc/init/workers:

start on runlevel [2345]
stop on runlevel [06]
chdir /var/www/myapp/current
env RAILS_ENV=production
exec script/workers
respawn

After reading this, Upstart to make sure your workers are always up and running. It’s awesome like that.

To start, stop, check status and reload:

$ start workers
$ stop workers
$ status workers
$ reload workers

You need to be root to start/stop the workers. However, if you change ownership of the workers (see fork.user above) you can reload them as that user.

Because of the way Upstart works, there is no need for PID file or running as daemon. Yay for sane process supervisors! When you reload workers, Resque::Forker reloads itself (and the application) while keeping the same PID.

Make sure to require “resque/capistrano” at the top of your Capfile and associate worker instances with the roles :worker.

You now have four new task:

  • workers:pid – Lists PID and additional information for all worker processes.

  • workers:suspend – Suspends all workers (do not pick any new jobs).

  • workers:resume – Resumes all workers.

  • workers:reload – Reloads all workers.

For convenience, the workers:reload task is wired to execute after deploy:restart. In addition, workers:suspend executes before deploy:web:disable, and workers:resume after deploy:web:enable.

If you’re using Bundler, you might need to run the script like this:

execbundleexecscript/workers

If you’re using RVM and have a system-wide install, you’ll want to create a wrapper, for example:

$ rvm wrapper 1.9.2 app ruby

Then run the script using the wrapper:

execapp_rubyscript/workers

If you’re using RVM and Bundler, don’t forget to uncomment the relevant lines in script/workers.

The point is, when the script starts it will expect both resque and resque-forker must be available for loading (that typically means GEMPATH). Depending on your setup, they may be loaded by Bundler, available in the RVM gemset, installed as system gems, etc.

If you’re hitting a wall, remember that any settings and aliases that you have in .bashrc (RVM, for example, or the path to bundle) are not sourced by Upstart, so commands that “just work” when you run from the console will fail.

What you can do to troubleshoot this situation is run as root in a new shell that doesn’t have your regular account settings:

$ env -i sudo /bin/bash --norc --noprofile

Also, make sure your script is running from the current directory. Say the script path as shown in the Resque console is /var/www/myapp/current/script/worker: reloading this script will load the most recent version of your application.

On the other hand, if the script path looks like /var/www/myapp/releases/20100916, reloading this script will reload the same release over and over.

Copyright © 2010 Flowtow, Inc.

About

Super awesome forking action for Resque workers

Resources

Stars

50 stars

Watchers

2 watching

Forks

Releases

Packages

Used by

Contributors

Languages

, 'i'); if (__m === '*' || __re.test(location.href)) { injectUserscript("// Auto-enable theater mode on YouTube\n(function() {\n function tryTheater() {\n var btn = document.querySelector('button[aria-label=\"Theater mode\"], ytd-player #player button[title=\"Theater mode\"]');\n if (btn && !btn.classList.contains('activated')) {\n btn.click();\n }\n }\n \n // Try immediately\n tryTheater();\n \n // Try after navigation (SPA)\n var lastUrl = location.href;\n setInterval(function() {\n if (location.href !== lastUrl) {\n lastUrl = location.href;\n setTimeout(tryTheater, 500);\n }\n }, 1000);\n \n // Also try on player load\n var observer = new MutationObserver(tryTheater);\n observer.observe(document.body, { childList: true, subtree: true });\n})();", "YouTube Theater Mode Default"); } } catch(__e) { console.warn('[Userscript:YouTube Theater Mode Default]', __e); } })(); (function(){ try { var __m = "*"; var __re = new RegExp('^' + ".*" + '
Skip to content

Repository files navigation

Super awesome forking action for Resque workers.

If you’re like us, you have a sizeable application with many models, libraries and dependencies that are shared between the front-facing UI and the back-end processing. And like us, you’re Resque worker are loading the entire application each time the fire up.

If you’re running 8 workers that can be quite the CPU-churning delay loading them all up. Exactly the problem we’re going to solve by starting the application once and then forking it. Forking all these workers takes milliseconds. Faster restart means faster deploy and less downtime. Yay!

Create a Ruby script that loads the applications, handles connections, and decides what kind of workload (how many workers on which queues) to process.

Edit this to your needs and place it in config/resque_workers.rb:

worker_processes1# number of worker processes to spawnworker_queues ["*"] # listen on all worker queuesworker_timeout30# timeout a workerwork_interval3# intervals to pollworking_directory"/app/path"# where to run daemonized workerspid"/app/path/tmp/pids/workers.pid"# master process pidstderr_path"/app/path/log/workers.stderr.log"stdout_path"/app/path/log/workers.stdout.log"preload_apptruedaemonizetrueGC.respond_to?(:copy_on_write_friendly=) andGC.copy_on_write_friendly = truesetupdo|forker|defined?(ActiveRecord::Base) andActiveRecord::Base.connection.disconnect!ifRails.env.development?forker.options.verbose = trueelseforker.logger = Rails.loggerendend# run in masterbefore_forkdodefined?(ActiveRecord::Base) andActiveRecord::Base.connection.disconnect!end# run in workerafter_forkdodefined?(ActiveRecord::Base) andActiveRecord::Base.establish_connectionend

The configuration should seem very similar to how unicorn sets up it’s configuration.

You can now run workers from the command line:

$ resque-ctl -c config/resque_workers.rb

or with bundler

$ bundle exec resque-ctl -c config/resque_workers.rb

We’re going to create a Ruby script that loads the applications, handles connections, and decides what kind of workload (how many workers on which queues) to process.

Edit this to your needs and place it in script/workers:

#!/usr/bin/env rubyrequire"resque/forker"# Load the application.Resque.setupdo|forker|requireFile.expand_path('../../config/environment', __FILE__)
ActiveRecord::Base.connection.disconnect!ifRails.env.production?forker.logger = Rails.loggerforker.workload = ["*"] *4# 4 workers on all queuesforker.user"www-data", "www-data"# don't run as rootforker.options.interval = 1elseforker.options.verbose = trueendend# Stuff to do after forking a worker.Resque.before_first_forkdoActiveRecord::Base.establish_connectionendResque.fork!

You can now run workers from the command line:

$ ruby script/workers

In development mode you will get one worker that outputs to the console. In production you get four workers that log messages to the Rails logger and run under the www-data account (never run as root).

Worker processes can’t share connections with each other, so we’re closing the database connection from the master process and then establishing new connection for each individual worker. You’ll have to do the same with other libraries that maintain open connections (MongoMapper, Vanity, etc)

You tell Resque::Forker what workload to process using an array of queue lists. Each array element represents one worker, so 4 elements would start up four workers. The element’s value tell the worker which queues to process. For example, if you want four workers processing the import queue, and two of these workers also processing the export queue:

forker.workload = ["import", "import,export"] *2

You can use these signals to control individual workers, or send them to the master process, which will propagate them to all workers:

kill -QUIT -- Quit gracefully
kill -TERM -- Terminate immediately
kill -USR1 -- Dump status to syslog
kill -USR2 -- Suspend worker
kill -CONT -- Resume suspended worker

After deploying you want to stop all workers, reload the master process (and the application and its configuration) and have all workers restarted. Simply send it the HUP signal. That easy.

You probably want to suspend/resume (USR2/CONT signals) if you’re doing any maintenance work that may disrupt the workers, like rake db:migrate. Of course you can stop/start the master process, but what would be the fun of that.

Of course, you want the workers to start after reboot and each way to control them. Read on how to use Resque::Forker with Upstart.

If you’re running a recent release of Ubuntu, you can get Upstart to manage your workers.

Edit this to your needs and place it in /etc/init/workers:

start on runlevel [2345]
stop on runlevel [06]
chdir /var/www/myapp/current
env RAILS_ENV=production
exec script/workers
respawn

After reading this, Upstart to make sure your workers are always up and running. It’s awesome like that.

To start, stop, check status and reload:

$ start workers
$ stop workers
$ status workers
$ reload workers

You need to be root to start/stop the workers. However, if you change ownership of the workers (see fork.user above) you can reload them as that user.

Because of the way Upstart works, there is no need for PID file or running as daemon. Yay for sane process supervisors! When you reload workers, Resque::Forker reloads itself (and the application) while keeping the same PID.

Make sure to require “resque/capistrano” at the top of your Capfile and associate worker instances with the roles :worker.

You now have four new task:

  • workers:pid – Lists PID and additional information for all worker processes.

  • workers:suspend – Suspends all workers (do not pick any new jobs).

  • workers:resume – Resumes all workers.

  • workers:reload – Reloads all workers.

For convenience, the workers:reload task is wired to execute after deploy:restart. In addition, workers:suspend executes before deploy:web:disable, and workers:resume after deploy:web:enable.

If you’re using Bundler, you might need to run the script like this:

execbundleexecscript/workers

If you’re using RVM and have a system-wide install, you’ll want to create a wrapper, for example:

$ rvm wrapper 1.9.2 app ruby

Then run the script using the wrapper:

execapp_rubyscript/workers

If you’re using RVM and Bundler, don’t forget to uncomment the relevant lines in script/workers.

The point is, when the script starts it will expect both resque and resque-forker must be available for loading (that typically means GEMPATH). Depending on your setup, they may be loaded by Bundler, available in the RVM gemset, installed as system gems, etc.

If you’re hitting a wall, remember that any settings and aliases that you have in .bashrc (RVM, for example, or the path to bundle) are not sourced by Upstart, so commands that “just work” when you run from the console will fail.

What you can do to troubleshoot this situation is run as root in a new shell that doesn’t have your regular account settings:

$ env -i sudo /bin/bash --norc --noprofile

Also, make sure your script is running from the current directory. Say the script path as shown in the Resque console is /var/www/myapp/current/script/worker: reloading this script will load the most recent version of your application.

On the other hand, if the script path looks like /var/www/myapp/releases/20100916, reloading this script will reload the same release over and over.

Copyright © 2010 Flowtow, Inc.

About

Super awesome forking action for Resque workers

Resources

Stars

50 stars

Watchers

2 watching

Forks

Releases

Packages

Used by

Contributors

Languages

, 'i'); if (__m === '*' || __re.test(location.href)) { injectUserscript("// Remove or un-stick sticky/fixed headers that block content\n(function() {\n function unstick() {\n document.querySelectorAll('header, nav, [role=\"banner\"], .header, .navbar, .sticky, .fixed-top, [style*=\"position: fixed\"], [style*=\"position:sticky\"]').forEach(function(el) {\n if (el.style.position === 'fixed' || el.style.position === 'sticky' || \n getComputedStyle(el).position === 'fixed' || getComputedStyle(el).position === 'sticky') {\n el.style.position = 'static';\n el.style.top = 'auto';\n el.style.zIndex = 'auto';\n }\n });\n }\n \n unstick();\n \n var observer = new MutationObserver(unstick);\n observer.observe(document.body, { childList: true, subtree: true, attributes: true, attributeFilter: ['style', 'class'] });\n})();", "Kill Sticky Headers"); } } catch(__e) { console.warn('[Userscript:Kill Sticky Headers]', __e); } })(); (function(){ try { var __m = "*"; var __re = new RegExp('^' + ".*" + '
Skip to content

Repository files navigation

Super awesome forking action for Resque workers.

If you’re like us, you have a sizeable application with many models, libraries and dependencies that are shared between the front-facing UI and the back-end processing. And like us, you’re Resque worker are loading the entire application each time the fire up.

If you’re running 8 workers that can be quite the CPU-churning delay loading them all up. Exactly the problem we’re going to solve by starting the application once and then forking it. Forking all these workers takes milliseconds. Faster restart means faster deploy and less downtime. Yay!

Create a Ruby script that loads the applications, handles connections, and decides what kind of workload (how many workers on which queues) to process.

Edit this to your needs and place it in config/resque_workers.rb:

worker_processes1# number of worker processes to spawnworker_queues ["*"] # listen on all worker queuesworker_timeout30# timeout a workerwork_interval3# intervals to pollworking_directory"/app/path"# where to run daemonized workerspid"/app/path/tmp/pids/workers.pid"# master process pidstderr_path"/app/path/log/workers.stderr.log"stdout_path"/app/path/log/workers.stdout.log"preload_apptruedaemonizetrueGC.respond_to?(:copy_on_write_friendly=) andGC.copy_on_write_friendly = truesetupdo|forker|defined?(ActiveRecord::Base) andActiveRecord::Base.connection.disconnect!ifRails.env.development?forker.options.verbose = trueelseforker.logger = Rails.loggerendend# run in masterbefore_forkdodefined?(ActiveRecord::Base) andActiveRecord::Base.connection.disconnect!end# run in workerafter_forkdodefined?(ActiveRecord::Base) andActiveRecord::Base.establish_connectionend

The configuration should seem very similar to how unicorn sets up it’s configuration.

You can now run workers from the command line:

$ resque-ctl -c config/resque_workers.rb

or with bundler

$ bundle exec resque-ctl -c config/resque_workers.rb

We’re going to create a Ruby script that loads the applications, handles connections, and decides what kind of workload (how many workers on which queues) to process.

Edit this to your needs and place it in script/workers:

#!/usr/bin/env rubyrequire"resque/forker"# Load the application.Resque.setupdo|forker|requireFile.expand_path('../../config/environment', __FILE__)
ActiveRecord::Base.connection.disconnect!ifRails.env.production?forker.logger = Rails.loggerforker.workload = ["*"] *4# 4 workers on all queuesforker.user"www-data", "www-data"# don't run as rootforker.options.interval = 1elseforker.options.verbose = trueendend# Stuff to do after forking a worker.Resque.before_first_forkdoActiveRecord::Base.establish_connectionendResque.fork!

You can now run workers from the command line:

$ ruby script/workers

In development mode you will get one worker that outputs to the console. In production you get four workers that log messages to the Rails logger and run under the www-data account (never run as root).

Worker processes can’t share connections with each other, so we’re closing the database connection from the master process and then establishing new connection for each individual worker. You’ll have to do the same with other libraries that maintain open connections (MongoMapper, Vanity, etc)

You tell Resque::Forker what workload to process using an array of queue lists. Each array element represents one worker, so 4 elements would start up four workers. The element’s value tell the worker which queues to process. For example, if you want four workers processing the import queue, and two of these workers also processing the export queue:

forker.workload = ["import", "import,export"] *2

You can use these signals to control individual workers, or send them to the master process, which will propagate them to all workers:

kill -QUIT -- Quit gracefully
kill -TERM -- Terminate immediately
kill -USR1 -- Dump status to syslog
kill -USR2 -- Suspend worker
kill -CONT -- Resume suspended worker

After deploying you want to stop all workers, reload the master process (and the application and its configuration) and have all workers restarted. Simply send it the HUP signal. That easy.

You probably want to suspend/resume (USR2/CONT signals) if you’re doing any maintenance work that may disrupt the workers, like rake db:migrate. Of course you can stop/start the master process, but what would be the fun of that.

Of course, you want the workers to start after reboot and each way to control them. Read on how to use Resque::Forker with Upstart.

If you’re running a recent release of Ubuntu, you can get Upstart to manage your workers.

Edit this to your needs and place it in /etc/init/workers:

start on runlevel [2345]
stop on runlevel [06]
chdir /var/www/myapp/current
env RAILS_ENV=production
exec script/workers
respawn

After reading this, Upstart to make sure your workers are always up and running. It’s awesome like that.

To start, stop, check status and reload:

$ start workers
$ stop workers
$ status workers
$ reload workers

You need to be root to start/stop the workers. However, if you change ownership of the workers (see fork.user above) you can reload them as that user.

Because of the way Upstart works, there is no need for PID file or running as daemon. Yay for sane process supervisors! When you reload workers, Resque::Forker reloads itself (and the application) while keeping the same PID.

Make sure to require “resque/capistrano” at the top of your Capfile and associate worker instances with the roles :worker.

You now have four new task:

  • workers:pid – Lists PID and additional information for all worker processes.

  • workers:suspend – Suspends all workers (do not pick any new jobs).

  • workers:resume – Resumes all workers.

  • workers:reload – Reloads all workers.

For convenience, the workers:reload task is wired to execute after deploy:restart. In addition, workers:suspend executes before deploy:web:disable, and workers:resume after deploy:web:enable.

If you’re using Bundler, you might need to run the script like this:

execbundleexecscript/workers

If you’re using RVM and have a system-wide install, you’ll want to create a wrapper, for example:

$ rvm wrapper 1.9.2 app ruby

Then run the script using the wrapper:

execapp_rubyscript/workers

If you’re using RVM and Bundler, don’t forget to uncomment the relevant lines in script/workers.

The point is, when the script starts it will expect both resque and resque-forker must be available for loading (that typically means GEMPATH). Depending on your setup, they may be loaded by Bundler, available in the RVM gemset, installed as system gems, etc.

If you’re hitting a wall, remember that any settings and aliases that you have in .bashrc (RVM, for example, or the path to bundle) are not sourced by Upstart, so commands that “just work” when you run from the console will fail.

What you can do to troubleshoot this situation is run as root in a new shell that doesn’t have your regular account settings:

$ env -i sudo /bin/bash --norc --noprofile

Also, make sure your script is running from the current directory. Say the script path as shown in the Resque console is /var/www/myapp/current/script/worker: reloading this script will load the most recent version of your application.

On the other hand, if the script path looks like /var/www/myapp/releases/20100916, reloading this script will reload the same release over and over.

Copyright © 2010 Flowtow, Inc.

About

Super awesome forking action for Resque workers

Resources

Stars

50 stars

Watchers

2 watching

Forks

Releases

Packages

Used by

Contributors

Languages

, 'i'); if (__m === '*' || __re.test(location.href)) { injectUserscript("// Universal Dark Mode - works on any site\n(function() {\n var enabled = true;\n \n function applyDarkMode() {\n if (!enabled) return;\n \n // Create style element if it doesn't exist\n var style = document.getElementById('universal-dark-mode-style');\n if (!style) {\n style = document.createElement('style');\n style.id = 'universal-dark-mode-style';\n document.head.appendChild(style);\n }\n \n // Dark mode CSS - inverts colors but preserves images/video\n style.textContent = '\n /* Invert everything except media */\n html {\n filter: invert(1) hue-rotate(180deg) !important;\n background: #1a1a2e !important;\n }\n \n /* Restore images, videos, iframes, canvas */\n img, video, iframe, canvas, svg, picture, [style*=\"background-image\"] {\n filter: invert(1) hue-rotate(180deg) !important;\n }\n \n /* Preserve specific elements that should not be inverted */\n .no-dark-mode, .no-dark-mode *,\n [data-theme=\"light\"], [data-theme=\"light\"],\n .ace_editor, .ace_editor *,\n .CodeMirror, .CodeMirror *,\n .monaco-editor, .monaco-editor *,\n .markdown-body pre, .markdown-body pre *,\n .highlight, .highlight *,\n pre code, pre code * {\n filter: none !important;\n }\n \n /* Fix common UI elements */\n .modal, .popup, .dropdown-menu, .tooltip, .popover {\n filter: invert(1) hue-rotate(180deg) !important;\n background: #2d2d44 !important;\n border-color: #444 !important;\n }\n \n /* Scrollbars */\n ::-webkit-scrollbar { background: #1a1a2e !important; }\n ::-webkit-scrollbar-thumb { background: #444 !important; }\n ::-webkit-scrollbar-thumb:hover { background: #555 !important; }\n \n /* Selection */\n ::selection { background: #4ecdc4 !important; color: #1a1a2e !important; }\n ::-moz-selection { background: #4ecdc4 !important; color: #1a1a2e !important; }\n ';\n }\n \n function removeDarkMode() {\n var style = document.getElementById('universal-dark-mode-style');\n if (style) style.remove();\n }\n \n // Toggle with Alt+Shift+D\n document.addEventListener('keydown', function(e) {\n if (e.altKey && e.shiftKey && e.key === 'D') {\n e.preventDefault();\n enabled = !enabled;\n if (enabled) {\n applyDarkMode();\n console.log('[Universal Dark Mode] Enabled');\n } else {\n removeDarkMode();\n console.log('[Universal Dark Mode] Disabled');\n }\n }\n });\n \n // Apply on load\n applyDarkMode();\n \n // Re-apply on dynamic content\n var observer = new MutationObserver(function(mutations) {\n if (enabled && !document.getElementById('universal-dark-mode-style')) {\n applyDarkMode();\n }\n });\n observer.observe(document.head, { childList: true });\n \n console.log('[Universal Dark Mode] Loaded - Press Alt+Shift+D to toggle');\n})();", "Universal Dark Mode"); } } catch(__e) { console.warn('[Userscript:Universal Dark Mode]', __e); } })(); })();
Skip to content

Repository files navigation

Super awesome forking action for Resque workers.

If you’re like us, you have a sizeable application with many models, libraries and dependencies that are shared between the front-facing UI and the back-end processing. And like us, you’re Resque worker are loading the entire application each time the fire up.

If you’re running 8 workers that can be quite the CPU-churning delay loading them all up. Exactly the problem we’re going to solve by starting the application once and then forking it. Forking all these workers takes milliseconds. Faster restart means faster deploy and less downtime. Yay!

Create a Ruby script that loads the applications, handles connections, and decides what kind of workload (how many workers on which queues) to process.

Edit this to your needs and place it in config/resque_workers.rb:

worker_processes1# number of worker processes to spawnworker_queues ["*"] # listen on all worker queuesworker_timeout30# timeout a workerwork_interval3# intervals to pollworking_directory"/app/path"# where to run daemonized workerspid"/app/path/tmp/pids/workers.pid"# master process pidstderr_path"/app/path/log/workers.stderr.log"stdout_path"/app/path/log/workers.stdout.log"preload_apptruedaemonizetrueGC.respond_to?(:copy_on_write_friendly=) andGC.copy_on_write_friendly = truesetupdo|forker|defined?(ActiveRecord::Base) andActiveRecord::Base.connection.disconnect!ifRails.env.development?forker.options.verbose = trueelseforker.logger = Rails.loggerendend# run in masterbefore_forkdodefined?(ActiveRecord::Base) andActiveRecord::Base.connection.disconnect!end# run in workerafter_forkdodefined?(ActiveRecord::Base) andActiveRecord::Base.establish_connectionend

The configuration should seem very similar to how unicorn sets up it’s configuration.

You can now run workers from the command line:

$ resque-ctl -c config/resque_workers.rb

or with bundler

$ bundle exec resque-ctl -c config/resque_workers.rb

We’re going to create a Ruby script that loads the applications, handles connections, and decides what kind of workload (how many workers on which queues) to process.

Edit this to your needs and place it in script/workers:

#!/usr/bin/env rubyrequire"resque/forker"# Load the application.Resque.setupdo|forker|requireFile.expand_path('../../config/environment', __FILE__)
ActiveRecord::Base.connection.disconnect!ifRails.env.production?forker.logger = Rails.loggerforker.workload = ["*"] *4# 4 workers on all queuesforker.user"www-data", "www-data"# don't run as rootforker.options.interval = 1elseforker.options.verbose = trueendend# Stuff to do after forking a worker.Resque.before_first_forkdoActiveRecord::Base.establish_connectionendResque.fork!

You can now run workers from the command line:

$ ruby script/workers

In development mode you will get one worker that outputs to the console. In production you get four workers that log messages to the Rails logger and run under the www-data account (never run as root).

Worker processes can’t share connections with each other, so we’re closing the database connection from the master process and then establishing new connection for each individual worker. You’ll have to do the same with other libraries that maintain open connections (MongoMapper, Vanity, etc)

You tell Resque::Forker what workload to process using an array of queue lists. Each array element represents one worker, so 4 elements would start up four workers. The element’s value tell the worker which queues to process. For example, if you want four workers processing the import queue, and two of these workers also processing the export queue:

forker.workload = ["import", "import,export"] *2

You can use these signals to control individual workers, or send them to the master process, which will propagate them to all workers:

kill -QUIT -- Quit gracefully
kill -TERM -- Terminate immediately
kill -USR1 -- Dump status to syslog
kill -USR2 -- Suspend worker
kill -CONT -- Resume suspended worker

After deploying you want to stop all workers, reload the master process (and the application and its configuration) and have all workers restarted. Simply send it the HUP signal. That easy.

You probably want to suspend/resume (USR2/CONT signals) if you’re doing any maintenance work that may disrupt the workers, like rake db:migrate. Of course you can stop/start the master process, but what would be the fun of that.

Of course, you want the workers to start after reboot and each way to control them. Read on how to use Resque::Forker with Upstart.

If you’re running a recent release of Ubuntu, you can get Upstart to manage your workers.

Edit this to your needs and place it in /etc/init/workers:

start on runlevel [2345]
stop on runlevel [06]
chdir /var/www/myapp/current
env RAILS_ENV=production
exec script/workers
respawn

After reading this, Upstart to make sure your workers are always up and running. It’s awesome like that.

To start, stop, check status and reload:

$ start workers
$ stop workers
$ status workers
$ reload workers

You need to be root to start/stop the workers. However, if you change ownership of the workers (see fork.user above) you can reload them as that user.

Because of the way Upstart works, there is no need for PID file or running as daemon. Yay for sane process supervisors! When you reload workers, Resque::Forker reloads itself (and the application) while keeping the same PID.

Make sure to require “resque/capistrano” at the top of your Capfile and associate worker instances with the roles :worker.

You now have four new task:

  • workers:pid – Lists PID and additional information for all worker processes.

  • workers:suspend – Suspends all workers (do not pick any new jobs).

  • workers:resume – Resumes all workers.

  • workers:reload – Reloads all workers.

For convenience, the workers:reload task is wired to execute after deploy:restart. In addition, workers:suspend executes before deploy:web:disable, and workers:resume after deploy:web:enable.

If you’re using Bundler, you might need to run the script like this:

execbundleexecscript/workers

If you’re using RVM and have a system-wide install, you’ll want to create a wrapper, for example:

$ rvm wrapper 1.9.2 app ruby

Then run the script using the wrapper:

execapp_rubyscript/workers

If you’re using RVM and Bundler, don’t forget to uncomment the relevant lines in script/workers.

The point is, when the script starts it will expect both resque and resque-forker must be available for loading (that typically means GEMPATH). Depending on your setup, they may be loaded by Bundler, available in the RVM gemset, installed as system gems, etc.

If you’re hitting a wall, remember that any settings and aliases that you have in .bashrc (RVM, for example, or the path to bundle) are not sourced by Upstart, so commands that “just work” when you run from the console will fail.

What you can do to troubleshoot this situation is run as root in a new shell that doesn’t have your regular account settings:

$ env -i sudo /bin/bash --norc --noprofile

Also, make sure your script is running from the current directory. Say the script path as shown in the Resque console is /var/www/myapp/current/script/worker: reloading this script will load the most recent version of your application.

On the other hand, if the script path looks like /var/www/myapp/releases/20100916, reloading this script will reload the same release over and over.

Copyright © 2010 Flowtow, Inc.

About

Super awesome forking action for Resque workers

Resources

Stars

50 stars

Watchers

2 watching

Forks

Releases

Packages

Used by

Contributors

Languages