Class: Batchy::Batch

Inherits:
ActiveRecord::Base
  • Object
show all
Extended by:
StateMachine::MacroMethods
Defined in:
lib/batchy/batch.rb

Instance Attribute Summary collapse

Class Method Summary collapse

Instance Method Summary collapse

Constructor Details

#initialize(*args) ⇒ Batch

Set up callback queues and states



61
62
63
64
# File 'lib/batchy/batch.rb', line 61

def initialize *args
  create_callback_queues
  super
end

Instance Attribute Details

#ensure_callbacksObject (readonly)

Returns the value of attribute ensure_callbacks.



9
10
11
# File 'lib/batchy/batch.rb', line 9

def ensure_callbacks
  @ensure_callbacks
end

#failure_callbacksObject (readonly)

Returns the value of attribute failure_callbacks.



7
8
9
# File 'lib/batchy/batch.rb', line 7

def failure_callbacks
  @failure_callbacks
end

#ignore_callbacksObject (readonly)

Returns the value of attribute ignore_callbacks.



10
11
12
# File 'lib/batchy/batch.rb', line 10

def ignore_callbacks
  @ignore_callbacks
end

#success_callbacksObject (readonly)

Returns the value of attribute success_callbacks.



8
9
10
# File 'lib/batchy/batch.rb', line 8

def success_callbacks
  @success_callbacks
end

Class Method Details

.expiredObject

Return all expired batches that are still running



55
56
57
# File 'lib/batchy/batch.rb', line 55

def expired
  where('expire_at < ? and state = ?', DateTime.now, 'running')
end

Instance Method Details

#already_runningObject

Is there batch with the same guid already running?



67
68
69
70
71
# File 'lib/batchy/batch.rb', line 67

def already_running
  return false if guid.nil?

  duplicate_batches.count > 0
end

#clear_zombiesObject

Removes duplicate batches that are stuck in a running state



75
76
77
78
79
80
81
82
# File 'lib/batchy/batch.rb', line 75

def clear_zombies
  duplicate_batches(:limit_to_current_host => true).each do | dup |
    if not dup.process_running?
      dup.error = Batchy::Error.new("Process has died, moving to a finished state")
      dup.finish!
    end
  end
end

#duplicate_batches(*args) ⇒ Object

Find all batches with the same guid that are running.

limit_to_current_host

This option limit duplicate batches to the
current host.
Default: false

Raises:



92
93
94
95
96
97
98
99
100
101
102
103
104
105
# File 'lib/batchy/batch.rb', line 92

def duplicate_batches *args
  options = args.extract_options!
  options.reverse_merge! :limit_to_current_host => false

  raise Batchy::Error, "Can not check for duplicate batches on nil guid" if guid.nil?
  rel = self.class.where(:guid => guid, :state => "running")

  if options[:limit_to_current_host]
    rel = rel.where(:hostname => Socket.gethostname)
  end
  return rel if new_record?

  rel.where("id <> ?", id)
end

#errorObject

Conversely, the backtrace is added to the error after a read



116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
# File 'lib/batchy/batch.rb', line 116

def error
  err = read_attribute(:error)
  return err if err.blank?

  backtrace = read_attribute(:backtrace)
  if err.respond_to?(:set_backtrace)
    err.set_backtrace(backtrace) 
  else
    def err.backtrace
      nil
    end
  end

  err
end

#error=(err) ⇒ Object

When serializing an exception, the YAML library does not save the backtrace. To fix this, we’re saving both the error and backtrace when the error is saved



110
111
112
113
# File 'lib/batchy/batch.rb', line 110

def error=(err)
  write_attribute(:error, err)
  write_attribute(:backtrace, err.backtrace) if err.respond_to?(:backtrace)
end

#expired?Boolean

Is this batch expired

Returns:

  • (Boolean)


133
134
135
# File 'lib/batchy/batch.rb', line 133

def expired?
  expire_at < DateTime.now && state == 'running'
end

#has_errorsObject

Does this batch have errors?



138
139
140
# File 'lib/batchy/batch.rb', line 138

def has_errors
  error?
end

#invalid_duplicationObject

Is this an unwanted duplicate process?



150
151
152
# File 'lib/batchy/batch.rb', line 150

def invalid_duplication
  !Batchy.configure.allow_duplicates && already_running
end

#killObject

Issues a SIGTERM to the process running this batch



155
156
157
158
159
# File 'lib/batchy/batch.rb', line 155

def kill
  return false unless hostname == ::Socket.gethostname

  Process.kill('TERM', pid)
end

#kill!Object

Issue a SIGKILL to the process running this batch BE CAREFUL! This will kill your application or server if this batch has the same PID.



164
165
166
167
168
# File 'lib/batchy/batch.rb', line 164

def kill!
  return false unless hostname == ::Socket.gethostname
  
  Process.kill('KILL', pid)
end

#on_ensure(*args, &block) ⇒ Object

Adds a callback that runs no matter what the exit state of the batchy block



172
173
174
175
176
177
178
# File 'lib/batchy/batch.rb', line 172

def on_ensure *args, &block
  if block_given?
    @ensure_callbacks << block
  else
    @ensure_callbacks << args.shift
  end
end

#on_failure(*args, &block) ⇒ Object

Add a callback to run on failure of the batch



182
183
184
185
186
187
188
# File 'lib/batchy/batch.rb', line 182

def on_failure *args, &block
  if block_given?
    @failure_callbacks << block
  else
    @failure_callbacks << args.shift
  end
end

#on_ignore(*args, &block) ⇒ Object

Adds a callback that runs if the process is a duplicate



192
193
194
195
196
197
198
# File 'lib/batchy/batch.rb', line 192

def on_ignore *args, &block
  if block_given?
    @ignore_callbacks << block
  else
    @ignore_callbacks << args.shift
  end
end

#on_success(*args, &block) ⇒ Object

Add a callback to run on successful completion of the batch



202
203
204
205
206
207
208
# File 'lib/batchy/batch.rb', line 202

def on_success *args, &block
  if block_given?
    @success_callbacks << block
  else
    @success_callbacks << args.shift
  end
end

#process_running?Boolean

Checks to see if the process attached to this batch is active

Returns:

  • (Boolean)

Raises:



212
213
214
215
216
# File 'lib/batchy/batch.rb', line 212

def process_running?
  raise Batchy::Error, 'Current host does not match the host running the batch' unless Socket.gethostname == hostname

  not Sys::ProcTable.ps(pid).blank?
end

#run_ensure_callbacksObject

:nodoc:



219
220
221
222
223
224
225
226
# File 'lib/batchy/batch.rb', line 219

def run_ensure_callbacks
  Batchy.configure.global_ensure_callbacks.each do | ec |
    ec.call(self)
  end
  ensure_callbacks.each do | ec |
    ec.call(self)
  end
end

#run_failure_callbacksObject

:nodoc:



249
250
251
252
253
254
255
256
# File 'lib/batchy/batch.rb', line 249

def run_failure_callbacks
  Batchy.configure.global_failure_callbacks.each do | fc |
    fc.call(self)
  end
  failure_callbacks.each do | fc |
    fc.call(self)
  end
end

#run_ignore_callbacksObject

:nodoc:



229
230
231
232
233
234
235
236
# File 'lib/batchy/batch.rb', line 229

def run_ignore_callbacks
  Batchy.configure.global_ignore_callbacks.each do | ic |
    ic.call(self)
  end
  ignore_callbacks.each do | ic |
    ic.call(self)
  end
end

#run_success_callbacksObject

:nodoc:



239
240
241
242
243
244
245
246
# File 'lib/batchy/batch.rb', line 239

def run_success_callbacks
  Batchy.configure.global_success_callbacks.each do | sc |
    sc.call(self)
  end
  success_callbacks.each do | sc |
    sc.call(self)
  end
end

#was_stoppedObject

Was this errored through a StoppedError? See StoppedError for example uses



144
145
146
# File 'lib/batchy/batch.rb', line 144

def was_stopped
  has_errors and error.class == StoppedError
end