vidibus-recording 1.0.0 → 2.0.0
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.
- data/LICENSE +1 -1
- data/README.md +102 -0
- data/lib/generators/vidibus/recording_generator.rb +1 -1
- data/lib/generators/vidibus/templates/script +4 -2
- data/lib/vidibus/recording/backend/rtmpdump.rb +7 -4
- data/lib/vidibus/recording/capistrano/recipes.rb +1 -1
- data/lib/vidibus/recording/capistrano.rb +5 -5
- data/lib/vidibus/recording/daemon.rb +4 -4
- data/lib/vidibus/recording/mongoid.rb +15 -17
- data/lib/vidibus/recording/part.rb +4 -0
- data/lib/vidibus/recording/railtie.rb +9 -1
- data/lib/vidibus/recording/version.rb +1 -1
- data/lib/vidibus/recording/worker.rb +8 -9
- data/lib/vidibus/recording.rb +60 -1
- data/lib/vidibus-recording.rb +0 -14
- metadata +6 -8
- data/README.rdoc +0 -11
- data/lib/vidibus/recording/backend/railtie.rb +0 -1
- data/lib/vidibus/recording/monitoring_job.rb +0 -52
data/LICENSE
CHANGED
data/README.md
ADDED
@@ -0,0 +1,102 @@
|
|
1
|
+
# Vidibus::Recording
|
2
|
+
|
3
|
+
Allows recording of RTMP video streams. Uses RTMPdump. Requires at least Ruby 1.9.
|
4
|
+
|
5
|
+
This gem is part of [Vidibus](http://vidibus.org), an open source toolset for building distributed (video) applications.
|
6
|
+
|
7
|
+
|
8
|
+
## Installation
|
9
|
+
|
10
|
+
Add `gem 'vidibus-recording'` to the Gemfile of your application. Then call `bundle install` on your console.
|
11
|
+
|
12
|
+
|
13
|
+
## Usage
|
14
|
+
|
15
|
+
### Available methods
|
16
|
+
|
17
|
+
To control a recording, you may use these methods:
|
18
|
+
|
19
|
+
```ruby
|
20
|
+
recording.start # starts recording
|
21
|
+
recording.stop # stops recording
|
22
|
+
recording.resume # continues if recording has been started but is not running
|
23
|
+
recording.restart # erases recorded data and restarts recording
|
24
|
+
```
|
25
|
+
|
26
|
+
|
27
|
+
### Custom class names
|
28
|
+
|
29
|
+
This gem will set up a model `Recording` if Rails is around. If you want to use the recording logic inside of a custom model, you just have to include the module `Vidibus::Recording::Mongoid`:
|
30
|
+
|
31
|
+
```ruby
|
32
|
+
class MyCustomRecording
|
33
|
+
include Mongoid::Document
|
34
|
+
include Vidibus::Recording::Mongoid
|
35
|
+
end
|
36
|
+
```
|
37
|
+
|
38
|
+
|
39
|
+
### Monitoring
|
40
|
+
|
41
|
+
If the worker process does not receive data, it will halt the recording. To monitor and restart a recording perform `Vidibus::Recording.monitor`. Beware, this method is blocking, so better spawn the daemon.
|
42
|
+
|
43
|
+
|
44
|
+
#### Monitoring daemon
|
45
|
+
|
46
|
+
To run the monitor as daemon, this gem provides a shell script. Install it with
|
47
|
+
|
48
|
+
```
|
49
|
+
rails g vidibus:recording
|
50
|
+
```
|
51
|
+
|
52
|
+
The daemon requires that `gem 'daemons'` is installed. To spawn him, enter
|
53
|
+
|
54
|
+
```
|
55
|
+
script/recording start
|
56
|
+
```
|
57
|
+
|
58
|
+
#### Possible caveat
|
59
|
+
|
60
|
+
To monitor your custom recording classes, `Vidibus::Recording.monitor` requires that all classes that include `Vidibus::Recording::Mongoid` have been loaded.
|
61
|
+
|
62
|
+
Because Rails is autoloading almost everything in development, this requirement is not met without the help of a little hack: To trigger autoloading, the monitor collects all aforementioned class names from the `app` directory and constantizes them.
|
63
|
+
|
64
|
+
**So here's the caveat:** If you define custom recording models outside of the `app` directory, you'll have to let the listener know. An initializer is perfect for that:
|
65
|
+
|
66
|
+
```ruby
|
67
|
+
# Collect all recording models in lib, too
|
68
|
+
Vidibus::Recording.autoload_paths << '/lib/**/*.rb'
|
69
|
+
```
|
70
|
+
|
71
|
+
|
72
|
+
## Deployment
|
73
|
+
|
74
|
+
A Capistrano configuration is included. Require it in your Capistrano `config.rb`.
|
75
|
+
|
76
|
+
```ruby
|
77
|
+
require 'vidibus/recording/capistrano'
|
78
|
+
```
|
79
|
+
|
80
|
+
That will add a bunch of callback hooks.
|
81
|
+
|
82
|
+
```ruby
|
83
|
+
after 'deploy:stop', 'vidibus:recording:stop'
|
84
|
+
after 'deploy:start', 'vidibus:recording:start'
|
85
|
+
after 'deploy:restart', 'vidibus:recording:restart'
|
86
|
+
```
|
87
|
+
|
88
|
+
If you need more control over the callbacks, you may load just the recipes without the hooks.
|
89
|
+
|
90
|
+
```ruby
|
91
|
+
require 'vidibus/recording/capistrano/recipes'
|
92
|
+
```
|
93
|
+
|
94
|
+
|
95
|
+
## Testing
|
96
|
+
|
97
|
+
To test this gem, call `bundle install` and `bundle exec rspec spec` on your console.
|
98
|
+
|
99
|
+
|
100
|
+
## Copyright
|
101
|
+
|
102
|
+
© 2011-2013 André Pankratz. See LICENSE for details.
|
@@ -1,6 +1,8 @@
|
|
1
1
|
#!/usr/bin/env ruby
|
2
2
|
|
3
3
|
require File.expand_path('../../config/environment', __FILE__)
|
4
|
-
require 'vidibus/
|
4
|
+
require 'vidibus/recording/daemon'
|
5
5
|
|
6
|
-
Vidibus::
|
6
|
+
Vidibus::Recording.monitoring_interval = 1 # second
|
7
|
+
Vidibus::Recording.autoload_paths << Rails.root.join('app/**/*.rb')
|
8
|
+
Vidibus::Recording::Daemon.new(ARGV).daemonize
|
@@ -79,7 +79,7 @@ module Vidibus::Recording::Backend
|
|
79
79
|
end
|
80
80
|
end
|
81
81
|
|
82
|
-
#
|
82
|
+
# Detect error from stdout or stderr.
|
83
83
|
# Output delivered by rtmpdump looks like this:
|
84
84
|
#
|
85
85
|
# RTMPDump v2.4
|
@@ -88,9 +88,12 @@ module Vidibus::Recording::Backend
|
|
88
88
|
# ERROR: Problem accessing the DNS. (addr: whatever.domain)
|
89
89
|
#
|
90
90
|
def detect_error(string)
|
91
|
-
|
92
|
-
|
93
|
-
|
91
|
+
if error = string[/(?:ERROR\:\ (.+))/,1]
|
92
|
+
case error
|
93
|
+
when 'rtmp server sent error'
|
94
|
+
else
|
95
|
+
raise RuntimeError.new($1)
|
96
|
+
end
|
94
97
|
end
|
95
98
|
end
|
96
99
|
end
|
@@ -1,12 +1,12 @@
|
|
1
1
|
require 'vidibus/recording/capistrano/recipes'
|
2
2
|
|
3
|
-
# Run Capistrano Recipes for
|
3
|
+
# Run Capistrano Recipes for monitoring recordings.
|
4
4
|
#
|
5
5
|
# Load this file from your Capistrano config.rb:
|
6
|
-
# require 'vidibus/
|
6
|
+
# require 'vidibus/recording/capistrano'
|
7
7
|
#
|
8
8
|
Capistrano::Configuration.instance.load do
|
9
|
-
after 'deploy:stop', 'vidibus:
|
10
|
-
after 'deploy:start', 'vidibus:
|
11
|
-
after 'deploy:restart', 'vidibus:
|
9
|
+
after 'deploy:stop', 'vidibus:recording:stop'
|
10
|
+
after 'deploy:start', 'vidibus:recording:start'
|
11
|
+
after 'deploy:restart', 'vidibus:recording:restart'
|
12
12
|
end
|
@@ -6,7 +6,7 @@ end
|
|
6
6
|
require 'optparse'
|
7
7
|
|
8
8
|
module Vidibus
|
9
|
-
module
|
9
|
+
module Recording
|
10
10
|
class Daemon
|
11
11
|
|
12
12
|
def initialize(args)
|
@@ -34,10 +34,10 @@ module Vidibus
|
|
34
34
|
def run
|
35
35
|
Dir.chdir(Rails.root)
|
36
36
|
log = File.join(Rails.root, 'log', 'recording.log')
|
37
|
-
Vidibus::
|
38
|
-
Vidibus::
|
37
|
+
Vidibus::Recording.logger = ActiveSupport::BufferedLogger.new(log)
|
38
|
+
Vidibus::Recording.monitor
|
39
39
|
rescue => e
|
40
|
-
Vidibus::
|
40
|
+
Vidibus::Recording.logger.fatal(e)
|
41
41
|
STDERR.puts(e.message)
|
42
42
|
exit 1
|
43
43
|
end
|
@@ -1,3 +1,8 @@
|
|
1
|
+
require 'mongoid'
|
2
|
+
require 'vidibus-uuid'
|
3
|
+
require 'active_support/core_ext'
|
4
|
+
require 'delayed_job_mongoid'
|
5
|
+
|
1
6
|
module Vidibus::Recording
|
2
7
|
module Mongoid
|
3
8
|
extend ActiveSupport::Concern
|
@@ -10,7 +15,6 @@ module Vidibus::Recording
|
|
10
15
|
|
11
16
|
field :name
|
12
17
|
field :stream
|
13
|
-
# field :live, :type => Boolean
|
14
18
|
field :pid, :type => Integer
|
15
19
|
field :info, :type => Hash
|
16
20
|
field :size, :type => Integer
|
@@ -20,13 +24,17 @@ module Vidibus::Recording
|
|
20
24
|
field :started_at, :type => DateTime
|
21
25
|
field :stopped_at, :type => DateTime
|
22
26
|
field :failed_at, :type => DateTime
|
27
|
+
field :active, :type => Boolean, :default => false
|
23
28
|
field :running, :type => Boolean, :default => false
|
24
|
-
|
29
|
+
|
30
|
+
index :active
|
25
31
|
|
26
32
|
validates :name, :presence => true
|
27
33
|
validates :stream, :format => {:with => /^rtmp.*?:\/\/.+$/}
|
28
34
|
|
29
35
|
before_destroy :cleanup
|
36
|
+
|
37
|
+
scope :active, where(active: true)
|
30
38
|
end
|
31
39
|
|
32
40
|
# Starts a recording worker now, unless it has been done already.
|
@@ -35,8 +43,8 @@ module Vidibus::Recording
|
|
35
43
|
return false if done? || started?
|
36
44
|
if time == :now
|
37
45
|
self.started_at = Time.now
|
46
|
+
self.active = true
|
38
47
|
start_worker
|
39
|
-
start_monitoring_job
|
40
48
|
save!
|
41
49
|
else
|
42
50
|
schedule(time)
|
@@ -48,8 +56,8 @@ module Vidibus::Recording
|
|
48
56
|
return false if running? || !started?
|
49
57
|
self.stopped_at = nil
|
50
58
|
self.failed_at = nil
|
59
|
+
self.active = true
|
51
60
|
start_worker
|
52
|
-
start_monitoring_job
|
53
61
|
save!
|
54
62
|
end
|
55
63
|
|
@@ -67,7 +75,7 @@ module Vidibus::Recording
|
|
67
75
|
self.pid = nil
|
68
76
|
self.stopped_at = Time.now
|
69
77
|
self.running = false
|
70
|
-
self.
|
78
|
+
self.active = false
|
71
79
|
postprocess
|
72
80
|
end
|
73
81
|
|
@@ -89,6 +97,7 @@ module Vidibus::Recording
|
|
89
97
|
self.error = msg
|
90
98
|
self.failed_at = Time.now
|
91
99
|
self.running = false
|
100
|
+
self.active = false
|
92
101
|
postprocess
|
93
102
|
end
|
94
103
|
|
@@ -104,8 +113,7 @@ module Vidibus::Recording
|
|
104
113
|
:info,
|
105
114
|
:error,
|
106
115
|
:size,
|
107
|
-
:duration
|
108
|
-
:monitoring_job_identifier
|
116
|
+
:duration
|
109
117
|
].map {|a| blank[a] = nil }
|
110
118
|
update_attributes!(blank)
|
111
119
|
destroy_all_parts
|
@@ -222,16 +230,6 @@ module Vidibus::Recording
|
|
222
230
|
self.pid = worker.pid
|
223
231
|
end
|
224
232
|
|
225
|
-
# Start a new monitoring job
|
226
|
-
def start_monitoring_job
|
227
|
-
self.monitoring_job_identifier = Vidibus::Uuid.generate
|
228
|
-
Vidibus::Recording::MonitoringJob.create({
|
229
|
-
:class_name => self.class.to_s,
|
230
|
-
:uuid => uuid,
|
231
|
-
:identifier => monitoring_job_identifier
|
232
|
-
})
|
233
|
-
end
|
234
|
-
|
235
233
|
def setup_next_part
|
236
234
|
number = nil
|
237
235
|
if current_part
|
@@ -1,11 +1,12 @@
|
|
1
|
+
require 'open3'
|
1
2
|
require 'timeout'
|
2
3
|
|
3
4
|
module Vidibus::Recording
|
4
5
|
class Worker
|
5
6
|
class ProcessError < StandardError; end
|
6
7
|
|
7
|
-
|
8
|
-
STOP_TIMEOUT =
|
8
|
+
START_TIMEOUT = 20
|
9
|
+
STOP_TIMEOUT = 2
|
9
10
|
|
10
11
|
attr_accessor :recording, :pid, :metadata
|
11
12
|
|
@@ -33,8 +34,7 @@ module Vidibus::Recording
|
|
33
34
|
Timeout::timeout(STOP_TIMEOUT) do
|
34
35
|
begin
|
35
36
|
log("Stopping process #{pid}...")
|
36
|
-
|
37
|
-
Process.kill('SIGQUIT', pid)
|
37
|
+
Process.kill('SIGTERM', pid)
|
38
38
|
Process.wait(pid)
|
39
39
|
log('STOPPED')
|
40
40
|
rescue Errno::ECHILD
|
@@ -73,8 +73,8 @@ module Vidibus::Recording
|
|
73
73
|
def record
|
74
74
|
cmd = recording.backend.command
|
75
75
|
log("START: #{recording.stream}", true)
|
76
|
+
timeout = Time.now + START_TIMEOUT
|
76
77
|
Open3::popen3(cmd) do |stdin, stdout, stderr|
|
77
|
-
maxloops = 10
|
78
78
|
loop do
|
79
79
|
begin
|
80
80
|
string = stdout.read_nonblock(1024).force_encoding('UTF-8')
|
@@ -90,12 +90,11 @@ module Vidibus::Recording
|
|
90
90
|
fail(e.message) && break
|
91
91
|
end
|
92
92
|
unless metadata
|
93
|
-
|
94
|
-
|
95
|
-
halt('No Metadata has been received so far.') && break
|
93
|
+
if Time.now > timeout
|
94
|
+
halt('No Metadata has been received so far, exiting.') && break
|
96
95
|
end
|
97
96
|
end
|
98
|
-
sleep
|
97
|
+
sleep(2)
|
99
98
|
end
|
100
99
|
end
|
101
100
|
end
|
data/lib/vidibus/recording.rb
CHANGED
@@ -1,6 +1,65 @@
|
|
1
1
|
require 'vidibus/recording/worker'
|
2
|
-
require 'vidibus/recording/monitoring_job'
|
3
2
|
require 'vidibus/recording/backend'
|
4
3
|
require 'vidibus/recording/helpers'
|
5
4
|
require 'vidibus/recording/part'
|
6
5
|
require 'vidibus/recording/mongoid'
|
6
|
+
require 'vidibus/recording/railtie' if defined?(Rails::Railtie)
|
7
|
+
|
8
|
+
module Vidibus
|
9
|
+
module Recording
|
10
|
+
extend self
|
11
|
+
|
12
|
+
class Error < StandardError; end
|
13
|
+
|
14
|
+
INTERVAL = 1
|
15
|
+
|
16
|
+
attr_accessor :logger, :autoload_paths, :classes, :monitoring_interval
|
17
|
+
@logger = Logger.new(STDOUT)
|
18
|
+
@autoload_paths = []
|
19
|
+
@classes = []
|
20
|
+
@monitoring_interval = 1
|
21
|
+
|
22
|
+
# Monitor all started recordings
|
23
|
+
def monitor
|
24
|
+
autoload
|
25
|
+
unless classes.any?
|
26
|
+
logger.error("[#{Time.now.utc}] - No recording classes given")
|
27
|
+
else
|
28
|
+
logger.info("[#{Time.now.utc}] - Watching recordings")
|
29
|
+
run
|
30
|
+
end
|
31
|
+
end
|
32
|
+
|
33
|
+
# Obtain all classes that include the Mongoid module
|
34
|
+
def autoload
|
35
|
+
return [] unless autoload_paths.any?
|
36
|
+
regexp = /class ([^<\n]+).+include Vidibus::Recording::Mongoid/m
|
37
|
+
names = Dir[*autoload_paths].map do |f|
|
38
|
+
File.read(f)[regexp, 1]
|
39
|
+
end.compact
|
40
|
+
self.classes = names.map { |k| k.constantize }
|
41
|
+
end
|
42
|
+
|
43
|
+
private
|
44
|
+
|
45
|
+
def run
|
46
|
+
loop do
|
47
|
+
classes.each do |klass|
|
48
|
+
klass.active.each do |recording|
|
49
|
+
begin
|
50
|
+
if recording.worker_running?
|
51
|
+
recording.track_progress
|
52
|
+
else
|
53
|
+
logger.info("[#{Time.now.utc}] - Resuming #{recording.class.name} #{recording.uuid}")
|
54
|
+
recording.resume
|
55
|
+
end
|
56
|
+
rescue => e
|
57
|
+
logger.error("[#{Time.now.utc}] - ERROR:\n#{e.inspect}\n---\n#{e.backtrace.join("\n")}")
|
58
|
+
end
|
59
|
+
end
|
60
|
+
end
|
61
|
+
sleep(monitoring_interval)
|
62
|
+
end
|
63
|
+
end
|
64
|
+
end
|
65
|
+
end
|
data/lib/vidibus-recording.rb
CHANGED
@@ -1,15 +1 @@
|
|
1
|
-
require 'open3'
|
2
|
-
require 'yaml'
|
3
|
-
require 'delayed_job_mongoid'
|
4
|
-
require 'active_support/core_ext'
|
5
|
-
require 'vidibus-uuid'
|
6
|
-
|
7
|
-
module Vidibus
|
8
|
-
module Recording
|
9
|
-
if defined?(Rails)
|
10
|
-
class Engine < ::Rails::Engine; end
|
11
|
-
end
|
12
|
-
end
|
13
|
-
end
|
14
|
-
|
15
1
|
require 'vidibus/recording'
|
metadata
CHANGED
@@ -1,7 +1,7 @@
|
|
1
1
|
--- !ruby/object:Gem::Specification
|
2
2
|
name: vidibus-recording
|
3
3
|
version: !ruby/object:Gem::Version
|
4
|
-
version:
|
4
|
+
version: 2.0.0
|
5
5
|
prerelease:
|
6
6
|
platform: ruby
|
7
7
|
authors:
|
@@ -9,7 +9,7 @@ authors:
|
|
9
9
|
autorequire:
|
10
10
|
bindir: bin
|
11
11
|
cert_chain: []
|
12
|
-
date: 2013-
|
12
|
+
date: 2013-08-01 00:00:00.000000000 Z
|
13
13
|
dependencies:
|
14
14
|
- !ruby/object:Gem::Dependency
|
15
15
|
name: activesupport
|
@@ -34,7 +34,7 @@ dependencies:
|
|
34
34
|
requirements:
|
35
35
|
- - ~>
|
36
36
|
- !ruby/object:Gem::Version
|
37
|
-
version: '2'
|
37
|
+
version: '2.5'
|
38
38
|
type: :runtime
|
39
39
|
prerelease: false
|
40
40
|
version_requirements: !ruby/object:Gem::Requirement
|
@@ -42,7 +42,7 @@ dependencies:
|
|
42
42
|
requirements:
|
43
43
|
- - ~>
|
44
44
|
- !ruby/object:Gem::Version
|
45
|
-
version: '2'
|
45
|
+
version: '2.5'
|
46
46
|
- !ruby/object:Gem::Dependency
|
47
47
|
name: delayed_job_mongoid
|
48
48
|
requirement: !ruby/object:Gem::Requirement
|
@@ -179,7 +179,6 @@ extra_rdoc_files: []
|
|
179
179
|
files:
|
180
180
|
- lib/generators/vidibus/recording_generator.rb
|
181
181
|
- lib/generators/vidibus/templates/script
|
182
|
-
- lib/vidibus/recording/backend/railtie.rb
|
183
182
|
- lib/vidibus/recording/backend/rtmpdump.rb
|
184
183
|
- lib/vidibus/recording/backend.rb
|
185
184
|
- lib/vidibus/recording/capistrano/recipes.rb
|
@@ -187,7 +186,6 @@ files:
|
|
187
186
|
- lib/vidibus/recording/daemon.rb
|
188
187
|
- lib/vidibus/recording/helpers.rb
|
189
188
|
- lib/vidibus/recording/mongoid.rb
|
190
|
-
- lib/vidibus/recording/monitoring_job.rb
|
191
189
|
- lib/vidibus/recording/part.rb
|
192
190
|
- lib/vidibus/recording/railtie.rb
|
193
191
|
- lib/vidibus/recording/version.rb
|
@@ -196,7 +194,7 @@ files:
|
|
196
194
|
- lib/vidibus-recording.rb
|
197
195
|
- app/models/recording.rb
|
198
196
|
- LICENSE
|
199
|
-
- README.
|
197
|
+
- README.md
|
200
198
|
- Rakefile
|
201
199
|
homepage: https://github.com/vidibus/vidibus-recording
|
202
200
|
licenses: []
|
@@ -212,7 +210,7 @@ required_ruby_version: !ruby/object:Gem::Requirement
|
|
212
210
|
version: '0'
|
213
211
|
segments:
|
214
212
|
- 0
|
215
|
-
hash:
|
213
|
+
hash: 507116490268825761
|
216
214
|
required_rubygems_version: !ruby/object:Gem::Requirement
|
217
215
|
none: false
|
218
216
|
requirements:
|
data/README.rdoc
DELETED
@@ -1 +0,0 @@
|
|
1
|
-
railtie.rb
|
@@ -1,52 +0,0 @@
|
|
1
|
-
module Vidibus::Recording
|
2
|
-
class MonitoringJob
|
3
|
-
INTERVAL = 10.seconds
|
4
|
-
|
5
|
-
def initialize(args)
|
6
|
-
unless @uuid = args[:uuid]
|
7
|
-
raise(ArgumentError, 'No recording UUID given')
|
8
|
-
end
|
9
|
-
unless @class_name = args[:class_name]
|
10
|
-
raise(ArgumentError, 'Must provide class name of recording')
|
11
|
-
end
|
12
|
-
unless @identifier = args[:identifier]
|
13
|
-
raise(ArgumentError, 'Must provide identifier of monitoring job')
|
14
|
-
end
|
15
|
-
ensure_recording
|
16
|
-
end
|
17
|
-
|
18
|
-
def perform
|
19
|
-
r = recording.reload
|
20
|
-
return unless r.monitoring_job_identifier == @identifier
|
21
|
-
if r.worker_running?
|
22
|
-
r.track_progress
|
23
|
-
run_again
|
24
|
-
elsif !r.stopped?
|
25
|
-
r.resume
|
26
|
-
end
|
27
|
-
end
|
28
|
-
|
29
|
-
# Returns job
|
30
|
-
def self.create(args)
|
31
|
-
job = new(args)
|
32
|
-
Delayed::Job.enqueue(job)
|
33
|
-
end
|
34
|
-
|
35
|
-
private
|
36
|
-
|
37
|
-
def recording
|
38
|
-
@class_name.constantize.where(:uuid => @uuid).first
|
39
|
-
end
|
40
|
-
|
41
|
-
def ensure_recording
|
42
|
-
recording || raise(ArgumentError, 'No valid recording UUID given')
|
43
|
-
end
|
44
|
-
|
45
|
-
def run_again
|
46
|
-
obj = self.class.new({
|
47
|
-
:uuid => @uuid, :class_name => @class_name, :identifier => @identifier
|
48
|
-
})
|
49
|
-
Delayed::Job.enqueue(obj, 0, INTERVAL.from_now)
|
50
|
-
end
|
51
|
-
end
|
52
|
-
end
|