postburner 1.0.0.pre.5 → 1.0.0.pre.6

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 CHANGED
@@ -1,7 +1,7 @@
1
1
  ---
2
2
  SHA256:
3
- metadata.gz: 38e2982c4478f99aa0d19c58ac7455cdf82ff1c3707a154d1dbd0c3a1546ceb8
4
- data.tar.gz: 0d17bb9da882d8e1cf2cce7c1cddd508ddbc7531c037dd56b7e0c6d34bd40f5b
3
+ metadata.gz: a480ddab26850f1ecacc0f3c1ec75de82d8ac1f0acd2b4b7f0997dc5b3cc044c
4
+ data.tar.gz: 6d7ed3b8dd92df4d1064750c7eead44b8fa8d3c60887cb5c98771844a14f014d
5
5
  SHA512:
6
- metadata.gz: 28421eb19f5e288e43e9d455364906dabe0ee3ab024a230efb9aca19842ac3677c4b602788d8f0f7c67253f64e1b382d12a4f23756ff01ef2e43a5b51d478d55
7
- data.tar.gz: f13d5452e5394c3e6d8b9468d8863344f35049972fbe5eac6c20cbede12ddc7e9eb2a17538bccb626a7a00a744c567d33e59558f5e7309ab3ecf775bea3db5b9
6
+ metadata.gz: 92f61d683537fa34a3aec8c7a052eb2313476fa2b647760d909022b28d0171db89b90c572b73af7eef6438bb1fc462f457d4b44bad1d249064993f68269de7e1
7
+ data.tar.gz: 495c9b4fba775507dd54666ab964bfa4d41fcc6608c3499ab5f4cc24b4f0af9a2cb4265b18331b566d61fce1318b1b1bc6a7ed9bc05d73619c5d5dd5dbc1711b
data/README.md CHANGED
@@ -1352,6 +1352,91 @@ end
1352
1352
  ```
1353
1353
 
1354
1354
 
1355
+ ### Tube Statistics and Management
1356
+
1357
+ Postburner provides methods to inspect and manage Beanstalkd tubes:
1358
+
1359
+ **View tube statistics:**
1360
+
1361
+ ```ruby
1362
+ # View all tubes on the Beanstalkd server
1363
+ stats = Postburner.stats
1364
+ # => {
1365
+ # tubes: [
1366
+ # { name: "postburner.production.default", ready: 10, delayed: 5, buried: 0, reserved: 2, total: 17 },
1367
+ # { name: "postburner.production.critical", ready: 0, delayed: 0, buried: 0, reserved: 1, total: 1 }
1368
+ # ],
1369
+ # totals: { ready: 10, delayed: 5, buried: 0, reserved: 3, total: 18 }
1370
+ # }
1371
+
1372
+ # View specific tubes only
1373
+ stats = Postburner.stats(['postburner.production.critical'])
1374
+ # => { tubes: [...], totals: {...} }
1375
+ ```
1376
+
1377
+ **Clear jobs from tubes:**
1378
+
1379
+ For safety, `clear_jobs!` requires you to explicitly specify which tubes to clear. This prevents accidentally clearing tubes from other applications sharing the same Beanstalkd server.
1380
+
1381
+ ```ruby
1382
+ # Collect stats only (no clearing)
1383
+ result = Postburner.clear_jobs!
1384
+ # => { tubes: [...], totals: {...}, cleared: false }
1385
+
1386
+ # Clear specific tubes (must be in config/postburner.yml)
1387
+ result = Postburner.clear_jobs!(['postburner.production.default'])
1388
+ # => { tubes: [...], totals: {...}, cleared: true }
1389
+
1390
+ # Pretty-print JSON output
1391
+ Postburner.clear_jobs!(['postburner.production.default'], silent: false)
1392
+ # Outputs formatted JSON to stdout
1393
+
1394
+ # Silent mode (no output, just return data)
1395
+ result = Postburner.clear_jobs!(['postburner.production.default'], silent: true)
1396
+ ```
1397
+
1398
+ **Safety validation:**
1399
+
1400
+ Only tubes defined in your loaded configuration can be cleared. This prevents mistakes in multi-tenant Beanstalkd environments:
1401
+
1402
+ ```ruby
1403
+ # Error: trying to clear tube not in config
1404
+ Postburner.clear_jobs!(['postburner.production.other-app'])
1405
+ # => ArgumentError: Cannot clear tubes not in configuration.
1406
+ # Invalid tubes: postburner.production.other-app
1407
+ # Configured tubes: postburner.production.default, postburner.production.critical
1408
+ ```
1409
+
1410
+ **Shortcut using watched_tube_names:**
1411
+
1412
+ Clear all configured tubes at once:
1413
+
1414
+ ```ruby
1415
+ # Get all tubes from current configuration
1416
+ watched_tubes = Postburner.watched_tube_names
1417
+ # => ["postburner.production.default", "postburner.production.critical", "postburner.production.mailers"]
1418
+
1419
+ # Clear all configured tubes
1420
+ Postburner.clear_jobs!(watched_tubes, silent: true)
1421
+ # or
1422
+ Postburner.clear_jobs!(Postburner.watched_tube_names, silent: true)
1423
+ ```
1424
+
1425
+ **Low-level Connection API:**
1426
+
1427
+ For programmatic use without output formatting, use `Connection#clear_tubes!`:
1428
+
1429
+ ```ruby
1430
+ Postburner.connected do |conn|
1431
+ # Returns data only (no puts)
1432
+ result = conn.clear_tubes!(Postburner.watched_tube_names)
1433
+ # => { tubes: [...], totals: {...}, cleared: true }
1434
+
1435
+ # Same validation - must be in configuration
1436
+ result = conn.clear_tubes!(['postburner.production.default'])
1437
+ end
1438
+ ```
1439
+
1355
1440
  ## Web UI
1356
1441
 
1357
1442
  Mount the inspection interface:
@@ -159,9 +159,8 @@ module Postburner
159
159
  #debugger
160
160
 
161
161
  # Response must be a hash with an :id key (value can be nil)
162
- # Backburner returns symbol keys
163
162
  unless response.is_a?(Hash) && response.key?(:id)
164
- raise MalformedResponse, "Missing :id key in response: #{response.inspect}"
163
+ raise Postburner::Job::MalformedResponse, "Missing :id key in response: #{response.inspect}"
165
164
  end
166
165
 
167
166
  persist_metadata!(bkid: response[:id])
@@ -99,11 +99,18 @@ module Postburner
99
99
  if workers.size == 1
100
100
  worker_name = workers.keys.first
101
101
  else
102
- raise ArgumentError, "Configuration has multiple workers, but --worker not specified\nAvailable workers: #{workers.keys.join(', ')}\nUsage: bin/postburner --worker <name>"
102
+ raise ArgumentError, <<~ERROR
103
+ Configuration has multiple workers, but --worker not specified
104
+ Available workers: #{workers.keys.join(', ')}
105
+ Usage: bin/postburner --worker <name>
106
+ ERROR
103
107
  end
104
108
  else
105
109
  unless workers.key?(worker_name)
106
- raise ArgumentError, "Worker '#{worker_name}' not found in #{path}\nAvailable workers: #{workers.keys.join(', ')}"
110
+ raise ArgumentError, <<~ERROR
111
+ Worker '#{worker_name}' not found in #{path}
112
+ Available workers: #{workers.keys.join(', ')}
113
+ ERROR
107
114
  end
108
115
  end
109
116
 
@@ -88,6 +88,68 @@ module Postburner
88
88
  @pool = nil
89
89
  end
90
90
 
91
+ # Clears jobs from specified tubes or collects stats for all tubes.
92
+ #
93
+ # Low-level method that returns data only (no output to stdout).
94
+ # Delegates to Postburner.stats for collecting statistics.
95
+ # For user-facing output, use Postburner.clear_jobs! instead.
96
+ #
97
+ # SAFETY: Only allows clearing tubes that are defined in the loaded
98
+ # configuration (watched_tube_names). This prevents accidentally clearing
99
+ # tubes from other applications or environments.
100
+ #
101
+ # @param tube_names [Array<String>, nil] Array of tube names to clear, or nil to only collect stats
102
+ #
103
+ # @return [Hash] Statistics and results with keys:
104
+ # - tubes: Array of hashes with per-tube stats
105
+ # - totals: Hash with aggregated counts across all tubes
106
+ # - cleared: Boolean indicating if tubes were actually cleared
107
+ #
108
+ # @raise [ArgumentError] if tube_names contains tubes not in watched_tube_names
109
+ #
110
+ # @example Collect stats only (no clearing)
111
+ # result = conn.clear_tubes!
112
+ # result[:totals][:total] # => 42
113
+ #
114
+ # @example Clear configured tubes only
115
+ # result = conn.clear_tubes!(Postburner.watched_tube_names)
116
+ # result[:cleared] # => true
117
+ #
118
+ # @example Invalid tube raises error
119
+ # conn.clear_tubes!(['random-tube'])
120
+ # # => ArgumentError: Cannot clear tubes not in configuration
121
+ #
122
+ def clear_tubes!(tube_names = nil)
123
+ ensure_connected!
124
+
125
+ # Validate that tubes to clear are in the loaded configuration
126
+ if tube_names&.any?
127
+ watched = Postburner.watched_tube_names
128
+ invalid_tubes = tube_names - watched
129
+
130
+ if invalid_tubes.any?
131
+ raise ArgumentError, <<~ERROR
132
+ Cannot clear tubes not in configuration.
133
+ Invalid tubes: #{invalid_tubes.join(', ')}
134
+ Configured tubes: #{watched.join(', ')}
135
+ ERROR
136
+ end
137
+ end
138
+
139
+ # Get stats using Postburner.stats
140
+ result = Postburner.stats(tube_names)
141
+ result[:cleared] = tube_names&.any? ? true : false
142
+
143
+ # Actually clear if tube names were provided and validated
144
+ if tube_names&.any?
145
+ tube_names.each do |tube_name|
146
+ tubes[tube_name].clear
147
+ end
148
+ end
149
+
150
+ result
151
+ end
152
+
91
153
  private
92
154
 
93
155
  # Establishes connection to Beanstalkd.
@@ -64,8 +64,10 @@ module Postburner
64
64
  #
65
65
  def travel_to(time, &block)
66
66
  unless defined?(ActiveSupport::Testing::TimeHelpers)
67
- raise "ActiveSupport::Testing::TimeHelpers not available. " \
68
- "Postburner::TimeHelpers requires Rails testing helpers for time travel."
67
+ raise <<~ERROR
68
+ ActiveSupport::Testing::TimeHelpers not available.
69
+ Postburner::TimeHelpers requires Rails testing helpers for time travel.
70
+ ERROR
69
71
  end
70
72
 
71
73
  helper = Object.new.extend(ActiveSupport::Testing::TimeHelpers)
@@ -1,3 +1,3 @@
1
1
  module Postburner
2
- VERSION = '1.0.0.pre.5'
2
+ VERSION = '1.0.0.pre.6'
3
3
  end
data/lib/postburner.rb CHANGED
@@ -375,25 +375,50 @@ module Postburner
375
375
  end
376
376
  end
377
377
 
378
- # Removes all jobs from all tubes (not yet implemented).
378
+ # Clears jobs from specified tubes or shows stats for all tubes.
379
379
  #
380
- # This is a destructive operation intended for development/testing cleanup.
381
- # Requires confirmation string "CONFIRM" to prevent accidental execution.
380
+ # High-level method with formatted output. Delegates to Connection#clear_tubes!
381
+ # for the actual work, then pretty-prints the results.
382
382
  #
383
- # @param confirm [String] Must be exactly "CONFIRM" to execute
383
+ # SAFETY: Only allows clearing tubes that are defined in the loaded
384
+ # configuration. This prevents accidentally clearing tubes from other
385
+ # applications or environments sharing the same Beanstalkd server.
384
386
  #
385
- # @return [void]
387
+ # @param tube_names [Array<String>, nil] Array of tube names to clear, or nil to only show stats
388
+ # @param silent [Boolean] If true, suppress output to stdout (default: false)
386
389
  #
387
- # @example
388
- # Postburner.remove_all!("CONFIRM")
390
+ # @return [Hash] Statistics and results (see Connection#clear_tubes!)
391
+ #
392
+ # @raise [ArgumentError] if tube_names contains tubes not in watched_tube_names
393
+ #
394
+ # @example Show stats only (no clearing) - SAFE
395
+ # Postburner.clear_jobs!
396
+ # # Shows stats for ALL tubes on Beanstalkd, but doesn't clear anything
397
+ #
398
+ # @example Clear watched tubes only - SAFE
399
+ # Postburner.clear_jobs!(Postburner.watched_tube_names)
400
+ # # Only clears tubes defined in your config
389
401
  #
390
- # @note Currently a no-op - implementation pending
391
- # @todo Implement job removal from all tubes
402
+ # @example Trying to clear unconfigured tube - RAISES ERROR
403
+ # Postburner.clear_jobs!(['some-other-app-tube'])
404
+ # # => ArgumentError: Cannot clear tubes not in configuration
392
405
  #
393
- def self.remove_all!(confirm)
394
- return unless confirm == "CONFIRM"
406
+ # @example Silent mode (programmatic use)
407
+ # result = Postburner.clear_jobs!(Postburner.watched_tube_names, silent: true)
408
+ # result[:totals][:total] # => 42
409
+ #
410
+ # @see Connection#clear_tubes!
411
+ #
412
+ def self.clear_jobs!(tube_names = nil, silent: false)
413
+ require 'json'
414
+
415
+ result = connection.clear_tubes!(tube_names)
416
+
417
+ unless silent
418
+ puts JSON.pretty_generate(result)
419
+ end
395
420
 
396
- # TODO
421
+ result
397
422
  end
398
423
 
399
424
  # Returns array of watched tube names with environment prefix.
@@ -423,38 +448,82 @@ module Postburner
423
448
  @__watched_tubes ||= watched_tube_names.map { |tube_name| connection.tubes[tube_name] }
424
449
  end
425
450
 
426
- # Returns statistics and introspection data about Beanstalkd and configured queues.
451
+ # Returns detailed statistics about Beanstalkd tubes.
427
452
  #
428
- # Provides Beaneater tube instances for configured tubes and all tubes that exist
429
- # on the Beanstalkd server. Tube instances support introspection methods:
453
+ # Collects job counts (ready, delayed, buried, reserved) for each tube
454
+ # and provides aggregate totals across all tubes.
430
455
  #
431
- # - tube.name - Tube name
432
- # - tube.stats - Tube statistics hash (current-jobs-ready, current-jobs-buried, etc.)
433
- # - tube.peek_ready - Next ready job
434
- # - tube.peek_delayed - Next delayed job
435
- # - tube.peek_buried - Next buried job
436
- # - tube.kick(n) - Kick n buried jobs back to ready
437
- # - tube.pause(delay) - Pause tube for delay seconds
438
- # - tube.clear - Delete all jobs in tube
456
+ # @param tube_names [Array<String>, nil] Specific tube names to inspect, or nil for all tubes
439
457
  #
440
- # @return [Hash] Statistics hash with the following keys:
441
- # - watched_tubes: Array of configured/watched Beaneater::Tube instances
442
- # - tubes: Array of all Beaneater::Tube instances on the server
458
+ # @return [Hash] Statistics hash with keys:
459
+ # - tubes: Array of hashes with per-tube stats (name, ready, delayed, buried, reserved, total)
460
+ # - totals: Hash with aggregated counts across all tubes
443
461
  #
444
462
  # @raise [Beaneater::NotConnected] if connection to Beanstalkd fails
445
463
  #
446
- # @example
464
+ # @example Get stats for all tubes
447
465
  # stats = Postburner.stats
448
- # stats[:watched_tubes].each { |tube| puts "#{tube.name}: #{tube.stats}" }
449
- # stats[:tubes].first.peek_ready
466
+ # stats[:totals][:total] # => 42
467
+ # stats[:tubes].first[:name] # => "default"
468
+ #
469
+ # @example Get stats for specific tubes
470
+ # stats = Postburner.stats(Postburner.watched_tube_names)
471
+ # stats[:tubes].size # => 3
450
472
  #
451
- def self.stats
473
+ def self.stats(tube_names = nil)
452
474
  connected do |conn|
453
- {
454
- watched_tubes: self.watched_tubes,
455
- # Get all tube instances that exist on Beanstalkd
456
- tubes: conn.beanstalk.tubes.all
475
+ # Get tubes to inspect
476
+ tubes_to_inspect = if tube_names&.any?
477
+ tube_names.map { |name| conn.tubes[name] }
478
+ else
479
+ conn.beanstalk.tubes.all
480
+ end
481
+
482
+ result = {
483
+ tubes: [],
484
+ totals: {
485
+ ready: 0,
486
+ delayed: 0,
487
+ buried: 0,
488
+ reserved: 0,
489
+ total: 0
490
+ }
457
491
  }
492
+
493
+ # Collect stats from each tube
494
+ tubes_to_inspect.each do |tube|
495
+ begin
496
+ stats = tube.stats
497
+ # Beaneater returns a StatStruct; access the underlying hash
498
+ stats_hash = stats.instance_variable_get(:@hash) || {}
499
+
500
+ tube_data = {
501
+ name: tube.name,
502
+ ready: stats_hash['current-jobs-ready'] || 0,
503
+ delayed: stats_hash['current-jobs-delayed'] || 0,
504
+ buried: stats_hash['current-jobs-buried'] || 0,
505
+ reserved: stats_hash['current-jobs-reserved'] || 0,
506
+ total: (stats_hash['current-jobs-ready'] || 0) +
507
+ (stats_hash['current-jobs-delayed'] || 0) +
508
+ (stats_hash['current-jobs-buried'] || 0) +
509
+ (stats_hash['current-jobs-reserved'] || 0)
510
+ }
511
+ rescue Beaneater::NotFoundError
512
+ # Tube doesn't exist yet, skip it
513
+ next
514
+ end
515
+
516
+ result[:tubes] << tube_data
517
+
518
+ # Aggregate totals
519
+ result[:totals][:ready] += tube_data[:ready]
520
+ result[:totals][:delayed] += tube_data[:delayed]
521
+ result[:totals][:buried] += tube_data[:buried]
522
+ result[:totals][:reserved] += tube_data[:reserved]
523
+ result[:totals][:total] += tube_data[:total]
524
+ end
525
+
526
+ result
458
527
  end
459
528
  end
460
529
  end
metadata CHANGED
@@ -1,7 +1,7 @@
1
1
  --- !ruby/object:Gem::Specification
2
2
  name: postburner
3
3
  version: !ruby/object:Gem::Version
4
- version: 1.0.0.pre.5
4
+ version: 1.0.0.pre.6
5
5
  platform: ruby
6
6
  authors:
7
7
  - Matt Smith