postburner 0.9.0.rc.1 → 1.0.0.pre.1
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- checksums.yaml +4 -4
- data/README.md +1082 -507
- data/app/models/postburner/job.rb +163 -39
- data/app/models/postburner/tracked_job.rb +83 -0
- data/bin/postburner +91 -0
- data/bin/rails +14 -0
- data/config/environment.rb +3 -0
- data/config/postburner.yml +22 -0
- data/config/postburner.yml.example +142 -0
- data/lib/postburner/active_job/adapter.rb +163 -0
- data/lib/postburner/active_job/execution.rb +109 -0
- data/lib/postburner/active_job/payload.rb +157 -0
- data/lib/postburner/beanstalkd.rb +97 -0
- data/lib/postburner/configuration.rb +202 -0
- data/lib/postburner/connection.rb +113 -0
- data/lib/postburner/engine.rb +1 -1
- data/lib/postburner/queue_config.rb +151 -0
- data/lib/postburner/strategies/queue.rb +20 -6
- data/lib/postburner/tracked.rb +171 -0
- data/lib/postburner/version.rb +1 -1
- data/lib/postburner/workers/base.rb +210 -0
- data/lib/postburner/workers/worker.rb +480 -0
- data/lib/postburner.rb +78 -7
- metadata +43 -11
|
@@ -70,45 +70,13 @@ module Postburner
|
|
|
70
70
|
# @attr_reader [Array<Hash>] errata Array of error details with timestamps
|
|
71
71
|
# @attr_reader [Array<Hash>] logs Array of log entries with timestamps
|
|
72
72
|
#
|
|
73
|
-
# Module to override Backburner::Queue methods to return nil when setting values
|
|
74
|
-
# This prevents return values from interfering with callback definitions
|
|
75
|
-
module BackburnerQueueOverrides
|
|
76
|
-
def queue(name=nil)
|
|
77
|
-
result = super
|
|
78
|
-
name.nil? ? result : nil
|
|
79
|
-
end
|
|
80
|
-
|
|
81
|
-
def queue_priority(pri=nil)
|
|
82
|
-
result = super
|
|
83
|
-
pri.nil? ? result : nil
|
|
84
|
-
end
|
|
85
|
-
|
|
86
|
-
def queue_respond_timeout(ttr=nil)
|
|
87
|
-
result = super
|
|
88
|
-
ttr.nil? ? result : nil
|
|
89
|
-
end
|
|
90
|
-
|
|
91
|
-
def queue_max_job_retries(retries=nil)
|
|
92
|
-
result = super
|
|
93
|
-
retries.nil? ? result : nil
|
|
94
|
-
end
|
|
95
|
-
|
|
96
|
-
def queue_retry_delay(delay=nil)
|
|
97
|
-
result = super
|
|
98
|
-
delay.nil? ? result : nil
|
|
99
|
-
end
|
|
100
|
-
|
|
101
|
-
def queue_retry_delay_proc(proc=nil)
|
|
102
|
-
result = super
|
|
103
|
-
proc.nil? ? result : nil
|
|
104
|
-
end
|
|
105
|
-
end
|
|
106
|
-
|
|
107
73
|
class Job < ApplicationRecord
|
|
108
|
-
include
|
|
109
|
-
singleton_class.prepend BackburnerQueueOverrides
|
|
74
|
+
include QueueConfig
|
|
110
75
|
include Callbacks
|
|
111
76
|
|
|
77
|
+
# Instance-level queue configuration (overrides class-level defaults)
|
|
78
|
+
attr_writer :queue_priority, :queue_ttr
|
|
79
|
+
|
|
112
80
|
LOG_LEVELS = [
|
|
113
81
|
:debug,
|
|
114
82
|
:info,
|
|
@@ -524,7 +492,7 @@ module Postburner
|
|
|
524
492
|
# @return [Beaneater::Job, nil] Beanstalkd job object or nil if no bkid
|
|
525
493
|
#
|
|
526
494
|
# @example Direct Beanstalkd operations
|
|
527
|
-
# bk_job = job.
|
|
495
|
+
# bk_job = job.bk
|
|
528
496
|
# bk_job.stats # Get job statistics
|
|
529
497
|
# bk_job.bury # Bury the job
|
|
530
498
|
# bk_job.release(pri: 0) # Release with priority
|
|
@@ -533,7 +501,7 @@ module Postburner
|
|
|
533
501
|
# @see #delete!
|
|
534
502
|
# @see #kick!
|
|
535
503
|
#
|
|
536
|
-
def
|
|
504
|
+
def bk
|
|
537
505
|
return unless self.bkid.present?
|
|
538
506
|
return @_beanstalk_job if @_beanstalk_job
|
|
539
507
|
|
|
@@ -542,6 +510,8 @@ module Postburner
|
|
|
542
510
|
@_beanstalk_job
|
|
543
511
|
end
|
|
544
512
|
|
|
513
|
+
alias_method :beanstalk_job, :bk
|
|
514
|
+
|
|
545
515
|
# Returns the Beanstalkd job object with cache invalidation.
|
|
546
516
|
#
|
|
547
517
|
# Same as {#beanstalk_job} but clears the cached instance variable first,
|
|
@@ -554,11 +524,163 @@ module Postburner
|
|
|
554
524
|
#
|
|
555
525
|
# @see #beanstalk_job
|
|
556
526
|
#
|
|
557
|
-
def
|
|
527
|
+
def bk!
|
|
558
528
|
@_beanstalk_job = nil
|
|
559
529
|
self.beanstalk_job
|
|
560
530
|
end
|
|
561
531
|
|
|
532
|
+
alias_method :beanstalk_job!, :bk!
|
|
533
|
+
|
|
534
|
+
# Returns job statistics including Beanstalkd job state.
|
|
535
|
+
#
|
|
536
|
+
# Fetches current job state from Beanstalkd and returns combined statistics
|
|
537
|
+
# about the job's PostgreSQL record and its current Beanstalkd status.
|
|
538
|
+
#
|
|
539
|
+
# @return [Hash] Statistics hash with the following keys:
|
|
540
|
+
# - id: PostgreSQL job ID
|
|
541
|
+
# - bkid: Beanstalkd job ID
|
|
542
|
+
# - queue: Queue name configured for this job class (e.g., 'sleep-jobs')
|
|
543
|
+
# - tube: Derived tube name with environment prefix (e.g., 'postburner.development.sleep-jobs')
|
|
544
|
+
# - watched: Boolean indicating if tube is in configured watch list
|
|
545
|
+
# - beanstalk: Hash of Beanstalkd job statistics:
|
|
546
|
+
# - id: Beanstalkd job ID
|
|
547
|
+
# - tube: Tube name where job resides
|
|
548
|
+
# - state: Job state (ready, reserved, delayed, buried)
|
|
549
|
+
# - pri: Priority (0 = highest, 4294967295 = lowest)
|
|
550
|
+
# - age: Seconds since job was created
|
|
551
|
+
# - delay: Seconds remaining before job becomes ready (0 if ready now)
|
|
552
|
+
# - ttr: Time-to-run in seconds (time allowed for job processing)
|
|
553
|
+
# - time_left: Seconds remaining before job times out (0 if not reserved)
|
|
554
|
+
# - file: Binlog file number containing job
|
|
555
|
+
# - reserves: Number of times job has been reserved
|
|
556
|
+
# - timeouts: Number of times job has timed out during processing
|
|
557
|
+
# - releases: Number of times job has been released back to ready
|
|
558
|
+
# - buries: Number of times job has been buried
|
|
559
|
+
# - kicks: Number of times job has been kicked from buried/delayed
|
|
560
|
+
#
|
|
561
|
+
# @raise [Beaneater::NotFoundError] if job no longer exists in Beanstalkd
|
|
562
|
+
#
|
|
563
|
+
# @example
|
|
564
|
+
# job.stats
|
|
565
|
+
# # => {
|
|
566
|
+
# # id: 5,
|
|
567
|
+
# # bkid: 1,
|
|
568
|
+
# # queue: "sleep-jobs",
|
|
569
|
+
# # tube: "postburner.development.sleep-jobs",
|
|
570
|
+
# # watched: false,
|
|
571
|
+
# # beanstalk: {
|
|
572
|
+
# # id: 1,
|
|
573
|
+
# # tube: "postburner.development.sleep-jobs",
|
|
574
|
+
# # state: "ready",
|
|
575
|
+
# # pri: 50,
|
|
576
|
+
# # age: 1391,
|
|
577
|
+
# # delay: 0,
|
|
578
|
+
# # ttr: 120,
|
|
579
|
+
# # time_left: 0,
|
|
580
|
+
# # file: 0,
|
|
581
|
+
# # reserves: 0,
|
|
582
|
+
# # timeouts: 0,
|
|
583
|
+
# # releases: 0,
|
|
584
|
+
# # buries: 0,
|
|
585
|
+
# # kicks: 0
|
|
586
|
+
# # }
|
|
587
|
+
# # }
|
|
588
|
+
#
|
|
589
|
+
def stats
|
|
590
|
+
# Get configured watched tubes (expanded with environment prefix)
|
|
591
|
+
watched = Postburner.watched_tube_names.include?(self.tube_name)
|
|
592
|
+
|
|
593
|
+
{
|
|
594
|
+
id: self.id,
|
|
595
|
+
bkid: self.bkid,
|
|
596
|
+
queue: queue_name,
|
|
597
|
+
tube: tube_name,
|
|
598
|
+
watched: watched,
|
|
599
|
+
beanstalk: self.bk.stats.to_h.symbolize_keys,
|
|
600
|
+
}
|
|
601
|
+
end
|
|
602
|
+
|
|
603
|
+
alias_method :beanstalk_job_stats, :stats
|
|
604
|
+
|
|
605
|
+
# Returns the queue name for this job instance.
|
|
606
|
+
#
|
|
607
|
+
# Checks instance-level override first, then falls back to class-level configuration.
|
|
608
|
+
#
|
|
609
|
+
# @return [String] Queue name
|
|
610
|
+
#
|
|
611
|
+
# @example Class-level configuration
|
|
612
|
+
# class MyJob < Postburner::Job
|
|
613
|
+
# queue 'critical'
|
|
614
|
+
# end
|
|
615
|
+
# job = MyJob.create!(args: {})
|
|
616
|
+
# job.queue_name # => 'critical'
|
|
617
|
+
#
|
|
618
|
+
def queue_name
|
|
619
|
+
self.class.queue
|
|
620
|
+
end
|
|
621
|
+
|
|
622
|
+
# Returns the queue priority for this job instance.
|
|
623
|
+
#
|
|
624
|
+
# Checks instance-level override first, then falls back to class-level configuration.
|
|
625
|
+
#
|
|
626
|
+
# @return [Integer, nil] Priority (lower = higher priority)
|
|
627
|
+
#
|
|
628
|
+
# @example Instance-level override
|
|
629
|
+
# job = MyJob.create!(args: {}, queue_priority: 1500)
|
|
630
|
+
# job.queue_priority # => 1500
|
|
631
|
+
#
|
|
632
|
+
def queue_priority
|
|
633
|
+
@queue_priority || self.class.queue_priority
|
|
634
|
+
end
|
|
635
|
+
|
|
636
|
+
# Returns the queue TTR (time-to-run) for this job instance.
|
|
637
|
+
#
|
|
638
|
+
# Checks instance-level override first, then falls back to class-level configuration.
|
|
639
|
+
#
|
|
640
|
+
# @return [Integer, nil] TTR in seconds
|
|
641
|
+
#
|
|
642
|
+
# @example Instance-level override
|
|
643
|
+
# job = MyJob.create!(args: {}, queue_ttr: 600)
|
|
644
|
+
# job.queue_ttr # => 600
|
|
645
|
+
#
|
|
646
|
+
def queue_ttr
|
|
647
|
+
@queue_ttr || self.class.queue_ttr
|
|
648
|
+
end
|
|
649
|
+
|
|
650
|
+
def tube_name
|
|
651
|
+
Postburner.configuration.expand_tube_name(queue_name)
|
|
652
|
+
end
|
|
653
|
+
|
|
654
|
+
# Extends the job's time-to-run (TTR) in Beanstalkd.
|
|
655
|
+
#
|
|
656
|
+
# Calls touch on the Beanstalkd job, extending the TTR by the original
|
|
657
|
+
# TTR value. Use this during long-running operations to prevent the job
|
|
658
|
+
# from timing out.
|
|
659
|
+
#
|
|
660
|
+
# @return [void]
|
|
661
|
+
#
|
|
662
|
+
# @note Does nothing if job has no bkid (e.g., in test mode)
|
|
663
|
+
#
|
|
664
|
+
# @example Process large file line by line
|
|
665
|
+
# def perform(args)
|
|
666
|
+
# file = File.find(args['file_id'])
|
|
667
|
+
# file.each_line do |line|
|
|
668
|
+
# # ... process line ...
|
|
669
|
+
# extend! # Extend TTR to prevent timeout
|
|
670
|
+
# end
|
|
671
|
+
# end
|
|
672
|
+
#
|
|
673
|
+
# @see #bk
|
|
674
|
+
#
|
|
675
|
+
def extend!
|
|
676
|
+
return unless self.bk
|
|
677
|
+
begin
|
|
678
|
+
self.bk.touch
|
|
679
|
+
rescue Beaneater::NotConnected => e
|
|
680
|
+
self.bk!.touch
|
|
681
|
+
end
|
|
682
|
+
end
|
|
683
|
+
|
|
562
684
|
# Tracks an exception in the job's errata array.
|
|
563
685
|
#
|
|
564
686
|
# Appends exception details to the in-memory errata array with timestamp,
|
|
@@ -797,6 +919,7 @@ module Postburner
|
|
|
797
919
|
# @api private
|
|
798
920
|
#
|
|
799
921
|
def insert_if_queued!
|
|
922
|
+
#debugger
|
|
800
923
|
return unless self.will_insert?
|
|
801
924
|
insert!(@_insert_options)
|
|
802
925
|
end
|
|
@@ -815,6 +938,7 @@ module Postburner
|
|
|
815
938
|
#
|
|
816
939
|
def insert!(options={})
|
|
817
940
|
response = Postburner.queue_strategy.insert(self, options)
|
|
941
|
+
#debugger
|
|
818
942
|
|
|
819
943
|
# Response must be a hash with an :id key (value can be nil)
|
|
820
944
|
# Backburner returns symbol keys
|
|
@@ -0,0 +1,83 @@
|
|
|
1
|
+
# frozen_string_literal: true
|
|
2
|
+
|
|
3
|
+
module Postburner
|
|
4
|
+
# Job wrapper for executing tracked ActiveJob instances.
|
|
5
|
+
#
|
|
6
|
+
# TrackedJob is a Postburner::Job subclass that deserializes and executes
|
|
7
|
+
# ActiveJob instances that opted-in to PostgreSQL tracking via the
|
|
8
|
+
# `Postburner::Tracked` concern.
|
|
9
|
+
#
|
|
10
|
+
# When an ActiveJob with `tracked` is enqueued, the adapter:
|
|
11
|
+
# 1. Creates a TrackedJob record in PostgreSQL
|
|
12
|
+
# 2. Stores the ActiveJob data in the `args` JSONB column
|
|
13
|
+
# 3. Queues a minimal payload to Beanstalkd with the TrackedJob ID
|
|
14
|
+
#
|
|
15
|
+
# When the worker executes the job:
|
|
16
|
+
# 1. Loads the TrackedJob record
|
|
17
|
+
# 2. Deserializes the ActiveJob from `args`
|
|
18
|
+
# 3. Executes it with full audit trail (logs, timing, errors)
|
|
19
|
+
#
|
|
20
|
+
# @example
|
|
21
|
+
# # User's ActiveJob (opts in to tracking)
|
|
22
|
+
# class ProcessPayment < ApplicationJob
|
|
23
|
+
# include Postburner::Tracked
|
|
24
|
+
# tracked
|
|
25
|
+
#
|
|
26
|
+
# def perform(payment_id)
|
|
27
|
+
# log "Processing payment #{payment_id}"
|
|
28
|
+
# # ...
|
|
29
|
+
# end
|
|
30
|
+
# end
|
|
31
|
+
#
|
|
32
|
+
# # ActiveJob adapter creates TrackedJob
|
|
33
|
+
# ProcessPayment.perform_later(123)
|
|
34
|
+
# # => Creates TrackedJob record, queues to Beanstalkd
|
|
35
|
+
#
|
|
36
|
+
# # Worker executes
|
|
37
|
+
# Postburner::Job.perform(tracked_job.id)
|
|
38
|
+
# # => Deserializes ProcessPayment job and executes with audit trail
|
|
39
|
+
#
|
|
40
|
+
class TrackedJob < Job
|
|
41
|
+
# Executes the wrapped ActiveJob instance.
|
|
42
|
+
#
|
|
43
|
+
# Deserializes the ActiveJob from args, restores metadata, sets up
|
|
44
|
+
# the bidirectional link for logging, and executes the job.
|
|
45
|
+
#
|
|
46
|
+
# @param args [Hash] JSONB args containing serialized ActiveJob data
|
|
47
|
+
#
|
|
48
|
+
# @return [void]
|
|
49
|
+
#
|
|
50
|
+
# @raise [Exception] Any exception raised by the ActiveJob is logged and re-raised
|
|
51
|
+
#
|
|
52
|
+
def perform(args)
|
|
53
|
+
# Extract ActiveJob metadata from args
|
|
54
|
+
job_class = args['job_class'].constantize
|
|
55
|
+
arguments = ::ActiveJob::Arguments.deserialize(args['arguments'])
|
|
56
|
+
|
|
57
|
+
# Instantiate the ActiveJob
|
|
58
|
+
job = job_class.new(*arguments)
|
|
59
|
+
|
|
60
|
+
# Restore ActiveJob metadata
|
|
61
|
+
job.job_id = args['job_id']
|
|
62
|
+
job.queue_name = args['queue_name']
|
|
63
|
+
job.priority = args['priority']
|
|
64
|
+
job.executions = args['executions'] || 0
|
|
65
|
+
job.exception_executions = args['exception_executions'] || {}
|
|
66
|
+
job.locale = args['locale']
|
|
67
|
+
job.timezone = args['timezone']
|
|
68
|
+
|
|
69
|
+
if args['enqueued_at']
|
|
70
|
+
job.enqueued_at = Time.iso8601(args['enqueued_at'])
|
|
71
|
+
end
|
|
72
|
+
|
|
73
|
+
# Give the ActiveJob access to this Postburner::Job for logging
|
|
74
|
+
if job.respond_to?(:postburner_job=)
|
|
75
|
+
job.postburner_job = self
|
|
76
|
+
end
|
|
77
|
+
|
|
78
|
+
# Execute the job (ActiveJob handles retry_on/discard_on)
|
|
79
|
+
# Exceptions are caught by Postburner::Job#perform! and logged to errata
|
|
80
|
+
job.perform_now
|
|
81
|
+
end
|
|
82
|
+
end
|
|
83
|
+
end
|
data/bin/postburner
ADDED
|
@@ -0,0 +1,91 @@
|
|
|
1
|
+
#!/usr/bin/env ruby
|
|
2
|
+
# frozen_string_literal: true
|
|
3
|
+
|
|
4
|
+
# Postburner worker executable
|
|
5
|
+
#
|
|
6
|
+
# Loads configuration from YAML and starts the appropriate worker type.
|
|
7
|
+
#
|
|
8
|
+
# Usage:
|
|
9
|
+
# bin/postburner [--config PATH] [--env ENVIRONMENT]
|
|
10
|
+
#
|
|
11
|
+
# Examples:
|
|
12
|
+
# bin/postburner
|
|
13
|
+
# bin/postburner --config config/postburner.yml --env production
|
|
14
|
+
#
|
|
15
|
+
|
|
16
|
+
require 'optparse'
|
|
17
|
+
|
|
18
|
+
# Parse command-line options
|
|
19
|
+
options = {
|
|
20
|
+
config: 'config/postburner.yml',
|
|
21
|
+
env: ENV['RAILS_ENV'] || ENV['RACK_ENV'] || 'development',
|
|
22
|
+
worker: nil,
|
|
23
|
+
queues: nil
|
|
24
|
+
}
|
|
25
|
+
|
|
26
|
+
OptionParser.new do |opts|
|
|
27
|
+
opts.banner = "Usage: bin/postburner [options]"
|
|
28
|
+
|
|
29
|
+
opts.on('-c', '--config PATH', 'Path to YAML configuration file (default: config/postburner.yml)') do |path|
|
|
30
|
+
options[:config] = path
|
|
31
|
+
end
|
|
32
|
+
|
|
33
|
+
opts.on('-e', '--env ENVIRONMENT', 'Environment (default: RAILS_ENV or development)') do |env|
|
|
34
|
+
options[:env] = env
|
|
35
|
+
end
|
|
36
|
+
|
|
37
|
+
opts.on('-w', '--worker WORKER', 'Worker name from config (required if multiple workers defined)') do |worker|
|
|
38
|
+
options[:worker] = worker
|
|
39
|
+
end
|
|
40
|
+
|
|
41
|
+
opts.on('-q', '--queues QUEUES', 'Comma-separated list of queues to process (default: all configured queues)') do |queues|
|
|
42
|
+
options[:queues] = queues.split(',').map(&:strip)
|
|
43
|
+
end
|
|
44
|
+
|
|
45
|
+
opts.on('-h', '--help', 'Show this help message') do
|
|
46
|
+
puts opts
|
|
47
|
+
exit
|
|
48
|
+
end
|
|
49
|
+
end.parse!
|
|
50
|
+
|
|
51
|
+
# Load Rails environment from current directory
|
|
52
|
+
# This executable should be run from your Rails application root
|
|
53
|
+
ENV['RAILS_ENV'] ||= options[:env]
|
|
54
|
+
require File.expand_path('config/environment', Dir.pwd)
|
|
55
|
+
|
|
56
|
+
# Postburner is loaded automatically via the Rails engine when the gem is in your Gemfile
|
|
57
|
+
|
|
58
|
+
# Load configuration
|
|
59
|
+
config_path = File.expand_path(options[:config], Dir.pwd)
|
|
60
|
+
|
|
61
|
+
begin
|
|
62
|
+
config = Postburner::Configuration.load_yaml(config_path, options[:env], options[:worker])
|
|
63
|
+
rescue ArgumentError => e
|
|
64
|
+
Rails.logger.error "[Postburner] ERROR: #{e.message}"
|
|
65
|
+
exit 1
|
|
66
|
+
end
|
|
67
|
+
|
|
68
|
+
# Filter queues if --queues option provided
|
|
69
|
+
if options[:queues]
|
|
70
|
+
# Validate that all specified queues exist in config
|
|
71
|
+
invalid_queues = options[:queues] - config.queue_names
|
|
72
|
+
unless invalid_queues.empty?
|
|
73
|
+
config.logger.error "[Postburner] ERROR: Unknown queue(s): #{invalid_queues.join(', ')}"
|
|
74
|
+
config.logger.error "[Postburner] Available queues: #{config.queue_names.join(', ')}"
|
|
75
|
+
exit 1
|
|
76
|
+
end
|
|
77
|
+
|
|
78
|
+
# Filter config to only include specified queues
|
|
79
|
+
filtered_queues = config.queues.select { |name, _| options[:queues].include?(name.to_s) }
|
|
80
|
+
config.queues = filtered_queues
|
|
81
|
+
end
|
|
82
|
+
|
|
83
|
+
config.logger.info "[Postburner] Configuration: #{config_path}"
|
|
84
|
+
config.logger.info "[Postburner] Environment: #{options[:env]}"
|
|
85
|
+
config.logger.info "[Postburner] Worker: #{options[:worker] || '(auto-selected)'}" if options[:worker] || options[:queues].nil?
|
|
86
|
+
config.logger.info "[Postburner] Queues: #{config.queue_names.join(', ')}"
|
|
87
|
+
config.logger.info "[Postburner] Defaults: forks=#{config.default_forks}, threads=#{config.default_threads}, gc_limit=#{config.default_gc_limit || 'none'}"
|
|
88
|
+
|
|
89
|
+
# Create and start worker
|
|
90
|
+
worker = Postburner::Workers::Worker.new(config)
|
|
91
|
+
worker.start
|
data/bin/rails
ADDED
|
@@ -0,0 +1,14 @@
|
|
|
1
|
+
#!/usr/bin/env ruby
|
|
2
|
+
# This command will automatically be run when you run "rails" with Rails gems
|
|
3
|
+
# installed from the root of your application.
|
|
4
|
+
|
|
5
|
+
ENGINE_ROOT = File.expand_path('..', __dir__)
|
|
6
|
+
ENGINE_PATH = File.expand_path('../lib/postburner/engine', __dir__)
|
|
7
|
+
APP_PATH = File.expand_path('../test/dummy/config/application', __dir__)
|
|
8
|
+
|
|
9
|
+
# Set up gems listed in the Gemfile.
|
|
10
|
+
ENV['BUNDLE_GEMFILE'] ||= File.expand_path('../Gemfile', __dir__)
|
|
11
|
+
require "bundler/setup" if File.exist?(ENV["BUNDLE_GEMFILE"])
|
|
12
|
+
|
|
13
|
+
require "rails/all"
|
|
14
|
+
require "rails/engine/commands"
|
data/config/environment.rb
CHANGED
|
@@ -0,0 +1,22 @@
|
|
|
1
|
+
development:
|
|
2
|
+
beanstalk_url: beanstalk://localhost:11300
|
|
3
|
+
worker_type: simple
|
|
4
|
+
queues:
|
|
5
|
+
default: {}
|
|
6
|
+
|
|
7
|
+
test:
|
|
8
|
+
beanstalk_url: beanstalk://localhost:11300
|
|
9
|
+
worker_type: simple
|
|
10
|
+
queues:
|
|
11
|
+
default: {}
|
|
12
|
+
|
|
13
|
+
production:
|
|
14
|
+
beanstalk_url: beanstalk://localhost:11300
|
|
15
|
+
worker_type: threads_on_fork
|
|
16
|
+
queues:
|
|
17
|
+
critical:
|
|
18
|
+
threads: 1
|
|
19
|
+
gc_limit: 100
|
|
20
|
+
default:
|
|
21
|
+
threads: 5
|
|
22
|
+
gc_limit: 500
|
|
@@ -0,0 +1,142 @@
|
|
|
1
|
+
# Postburner Configuration Example
|
|
2
|
+
#
|
|
3
|
+
# Copy this file to config/postburner.yml and customize for your environment.
|
|
4
|
+
#
|
|
5
|
+
# ## Named Workers Configuration
|
|
6
|
+
#
|
|
7
|
+
# Postburner uses named worker configurations to support different deployment patterns:
|
|
8
|
+
# - Single worker: bin/postburner (auto-selects the single worker)
|
|
9
|
+
# - Multiple workers: bin/postburner --worker <name> (must specify which worker)
|
|
10
|
+
#
|
|
11
|
+
# Each worker can have different fork/thread settings and process different queues.
|
|
12
|
+
# This enables running different queue groups in separate OS processes with distinct
|
|
13
|
+
# concurrency profiles.
|
|
14
|
+
#
|
|
15
|
+
# ## Puma-Style Architecture
|
|
16
|
+
#
|
|
17
|
+
# - **forks: 0** = Single process with thread pool (development/staging)
|
|
18
|
+
# - **forks: 1+** = Multiple processes with thread pools (production)
|
|
19
|
+
#
|
|
20
|
+
# Scale by adjusting forks and threads per worker:
|
|
21
|
+
# - Development: forks=0, threads=1 (single-threaded, easiest debugging)
|
|
22
|
+
# - Staging: forks=0, threads=10 (multi-threaded, moderate load)
|
|
23
|
+
# - Production: forks=4, threads=10 (40 concurrent jobs per queue)
|
|
24
|
+
#
|
|
25
|
+
|
|
26
|
+
default: &default
|
|
27
|
+
# Beanstalkd connection URL
|
|
28
|
+
# Override with ENV['BEANSTALK_URL'] if set
|
|
29
|
+
beanstalk_url: <%= ENV['BEANSTALK_URL'] || 'beanstalk://localhost:11300' %>
|
|
30
|
+
|
|
31
|
+
development:
|
|
32
|
+
<<: *default
|
|
33
|
+
|
|
34
|
+
workers:
|
|
35
|
+
default:
|
|
36
|
+
# Single-threaded, single process (simplest for debugging)
|
|
37
|
+
# Defaults: forks=0, threads=1, gc_limit=nil
|
|
38
|
+
queues:
|
|
39
|
+
- default
|
|
40
|
+
- mailers
|
|
41
|
+
|
|
42
|
+
test:
|
|
43
|
+
<<: *default
|
|
44
|
+
|
|
45
|
+
workers:
|
|
46
|
+
default:
|
|
47
|
+
# Test mode uses inline strategies automatically
|
|
48
|
+
# Defaults: forks=0, threads=1, gc_limit=nil
|
|
49
|
+
queues:
|
|
50
|
+
- default
|
|
51
|
+
|
|
52
|
+
staging:
|
|
53
|
+
<<: *default
|
|
54
|
+
|
|
55
|
+
workers:
|
|
56
|
+
default:
|
|
57
|
+
# Multi-threaded, single process (moderate concurrency)
|
|
58
|
+
default_threads: 10
|
|
59
|
+
default_gc_limit: 5000
|
|
60
|
+
queues:
|
|
61
|
+
- critical
|
|
62
|
+
- default
|
|
63
|
+
- mailers
|
|
64
|
+
|
|
65
|
+
production:
|
|
66
|
+
<<: *default
|
|
67
|
+
|
|
68
|
+
# Example 1: Single worker processing all queues with same settings
|
|
69
|
+
# Run: bin/postburner
|
|
70
|
+
#
|
|
71
|
+
# workers:
|
|
72
|
+
# default:
|
|
73
|
+
# default_forks: 4
|
|
74
|
+
# default_threads: 10
|
|
75
|
+
# default_gc_limit: 5000
|
|
76
|
+
# queues:
|
|
77
|
+
# - critical
|
|
78
|
+
# - default
|
|
79
|
+
# - mailers
|
|
80
|
+
# - imports
|
|
81
|
+
|
|
82
|
+
# Example 2: Multiple workers with different concurrency profiles
|
|
83
|
+
# Run separate processes:
|
|
84
|
+
# bin/postburner --worker imports (4 forks, 1 thread each)
|
|
85
|
+
# bin/postburner --worker general (2 forks, 100 threads each)
|
|
86
|
+
#
|
|
87
|
+
workers:
|
|
88
|
+
# Heavy, memory-intensive jobs - more processes, fewer threads
|
|
89
|
+
imports:
|
|
90
|
+
default_forks: 4
|
|
91
|
+
default_threads: 1
|
|
92
|
+
default_gc_limit: 500
|
|
93
|
+
queues:
|
|
94
|
+
- imports
|
|
95
|
+
- data_processing
|
|
96
|
+
|
|
97
|
+
# General jobs - fewer processes, many threads
|
|
98
|
+
general:
|
|
99
|
+
default_forks: 2
|
|
100
|
+
default_threads: 100
|
|
101
|
+
default_gc_limit: 5000
|
|
102
|
+
queues:
|
|
103
|
+
- default
|
|
104
|
+
- mailers
|
|
105
|
+
- notifications
|
|
106
|
+
|
|
107
|
+
# Example 3: Fine-grained control with multiple specialized workers
|
|
108
|
+
# Run separate processes:
|
|
109
|
+
# bin/postburner --worker critical
|
|
110
|
+
# bin/postburner --worker default
|
|
111
|
+
# bin/postburner --worker mailers
|
|
112
|
+
#
|
|
113
|
+
# workers:
|
|
114
|
+
# critical:
|
|
115
|
+
# default_forks: 1
|
|
116
|
+
# default_threads: 1
|
|
117
|
+
# default_gc_limit: 100
|
|
118
|
+
# queues:
|
|
119
|
+
# - critical
|
|
120
|
+
#
|
|
121
|
+
# default:
|
|
122
|
+
# default_forks: 4
|
|
123
|
+
# default_threads: 10
|
|
124
|
+
# default_gc_limit: 5000
|
|
125
|
+
# queues:
|
|
126
|
+
# - default
|
|
127
|
+
#
|
|
128
|
+
# mailers:
|
|
129
|
+
# default_forks: 2
|
|
130
|
+
# default_threads: 5
|
|
131
|
+
# default_gc_limit: 2000
|
|
132
|
+
# queues:
|
|
133
|
+
# - mailers
|
|
134
|
+
|
|
135
|
+
# Global Defaults (can be overridden per worker):
|
|
136
|
+
#
|
|
137
|
+
# default_queue: default # Default queue name (optional)
|
|
138
|
+
# default_priority: 65536 # Lower = higher priority (optional, 0 is highest)
|
|
139
|
+
# default_ttr: 300 # Time-to-run in seconds (optional)
|
|
140
|
+
# default_threads: 1 # Thread count per fork (optional, defaults to 1)
|
|
141
|
+
# default_forks: 0 # Fork count (optional, defaults to 0 = single process)
|
|
142
|
+
# default_gc_limit: nil # Exit after N jobs for restart (optional, nil = no limit)
|