Class: Eco::API::Session::Batch::Job

Inherits:
Common::Session::BaseSession show all
Includes:
Language::Methods::DslAble
Defined in:
lib/eco/api/session/batch/job.rb

Class Attribute Summary collapse

Instance Attribute Summary collapse

Attributes inherited from Common::Session::BaseSession

#config, #environment, #session

Attributes included from Language::AuxiliarLogger

#logger

Class Method Summary collapse

Instance Method Summary collapse

Methods included from Language::Methods::DslAble

#evaluate, #method_missing, #respond_to_missing?

Methods inherited from Common::Session::BaseSession

#api, #api?, #fatal, #file_manager, #logger, #mailer, #mailer?, #s3uploader, #s3uploader?, #sftp, #sftp?

Methods included from Language::AuxiliarLogger

#log

Constructor Details

#initialize(ev, name:, type:, sets:, usecase: nil, accept_update_with_no_id: false) ⇒ Job

Returns a new instance of Job.

Parameters:

  • ev (Eco::API::Common::Session::Environment)

    requires a session environment, as any child of Eco::API::Common::Session::BaseSession.

  • name (String)

    the name of this batch job

  • type (Symbol)

    a valid batch operation.

  • usecase (Eco::API::UseCases::UseCase, nil) (defaults to: nil)

    when provided: usecase that generated this batch job. This is necessary to know the options used to run the usecase, which could modify the Batch::Job behviour.

  • accept_update_with_no_id (Boolean) (defaults to: false)

    temporary contingency This parameter has been added due to a bug on server side. An external_id is still required.



49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
# File 'lib/eco/api/session/batch/job.rb', line 49

def initialize(ev, name:, type:, sets:, usecase: nil, accept_update_with_no_id: false)
  msg = "A name is required to refer a job. Given: '#{name}'"
  raise msg unless name

  msg = "Type should be one of #{self.class.types}. Given: #{type}"
  raise msg unless self.class.valid_type?(type)

  msg = "Sets should be some of #{self.class.sets}. Given: #{sets}"
  raise msg unless self.class.valid_sets?(sets)

  msg = "usecase must be a Eco::API::UseCases::UseCase object. Given: #{usecase.class}"
  raise msg if usecase && !usecase.is_a?(Eco::API::UseCases::UseCase)

  super(ev)

  @name     = name
  @type     = type
  @sets     = [sets].flatten.compact
  @usecase  = usecase
  @feedback = Eco::API::Session::Batch::Feedback.new(job: self)
  @accept_update_with_no_id = accept_update_with_no_id
  reset
end

Dynamic Method Handling

This class handles dynamic methods through the method_missing method in the class Eco::Language::Methods::DslAble

Class Attribute Details

.setsObject (readonly)

Returns the value of attribute sets.



23
24
25
# File 'lib/eco/api/session/batch/job.rb', line 23

def sets
  @sets
end

.typesObject (readonly)

Returns the value of attribute types.



23
24
25
# File 'lib/eco/api/session/batch/job.rb', line 23

def types
  @types
end

Instance Attribute Details

#feedbackEco::API::Session::Batch::Feedback (readonly)

helper class for feedback and end-user decision making

Returns:



16
17
18
# File 'lib/eco/api/session/batch/job.rb', line 16

def feedback
  @feedback
end

#nameString (readonly)

the name of this batch job

Returns:

  • (String)

    the current value of name



16
17
18
# File 'lib/eco/api/session/batch/job.rb', line 16

def name
  @name
end

#setsArray<Symbol> (readonly)

the parts of the person model this batch is supposed to affect

Returns:

  • (Array<Symbol>)

    the current value of sets



16
17
18
# File 'lib/eco/api/session/batch/job.rb', line 16

def sets
  @sets
end

#statusEco::API::Session::Batch::Status (readonly)

if launched: the status of the batch

Returns:



16
17
18
# File 'lib/eco/api/session/batch/job.rb', line 16

def status
  @status
end

#typeSymbol (readonly)

a valid batch operation

Returns:

  • (Symbol)

    the current value of type



16
17
18
# File 'lib/eco/api/session/batch/job.rb', line 16

def type
  @type
end

#usecaseEco::API::UseCases::UseCase? (readonly)

when provided: usecase that generated this batch job

Returns:



16
17
18
# File 'lib/eco/api/session/batch/job.rb', line 16

def usecase
  @usecase
end

Class Method Details

.valid_sets?(value) ⇒ Boolean

Returns:

  • (Boolean)


29
30
31
32
# File 'lib/eco/api/session/batch/job.rb', line 29

def valid_sets?(value)
  sts = [value].flatten
  sts.all? { |s| sets.include?(s) }
end

.valid_type?(value) ⇒ Boolean

Returns:

  • (Boolean)


25
26
27
# File 'lib/eco/api/session/batch/job.rb', line 25

def valid_type?(value)
  types.include?(value)
end

Instance Method Details

#add(entry, unique: true) {|person| ... } ⇒ Eco::API::Session::Batch::Job

Adds an entry(ies) to the job queue.

Parameters:

  • entry (Ecoportal::API::V1::Person, Enumerable<Person>)

    the person(s) we want to update, carrying the changes to be done.

  • unique (Boolean) (defaults to: true)

    specifies if repeated entries should be avoided in the queue.

Yields:

  • (person)

    callback before launching the batch job request against the server.

Yield Parameters:

  • person (Person)

    current person object that that should be treated by the callback before launching the batch.

Returns:



128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
# File 'lib/eco/api/session/batch/job.rb', line 128

def add(entry, unique: true, &block)
  case entry
  when Enumerable
    entry.each {|el| add(el, unique: unique, &block)}
  else
    return self unless entry
    return self if unique && @queue_hash.key?(entry)

    @queue_hash[entry] = true
    @queue.push(entry)
    @callbacks[entry] = block if block_given?
  end

  self
end

#dup(name = "ad-hoc:job-from:#{self.name}", usecase: self.usecase) ⇒ Eco::API::Session::Batch::Job

Note:
  • this job will not be linked to the Batch::Jobs model of the current session
  • mostly used for error_handlers

Creates an empty Batch::Job with same behaviour as the current one



86
87
88
89
90
91
92
93
94
# File 'lib/eco/api/session/batch/job.rb', line 86

def dup(name = "ad-hoc:job-from:#{self.name}", usecase: self.usecase)
  self.class.new(
    enviro,
    name:    name,
    type:    type,
    sets:    sets,
    usecase: usecase
  )
end

#ensure_requests!Object

Note:

some times we need a summary of what actually is going to be run without invoking launch (i.e. when there's a uncompliance with the batch policy)



152
153
154
155
156
157
# File 'lib/eco/api/session/batch/job.rb', line 152

def ensure_requests!
  return if instance_variable_defined?(:@requests)

  pqueue    = processed_queue
  @requests = as_update(pqueue)
end

#error_handler?Boolean

Returns true if the current batch job is a result of an error_handler.

Returns:

  • (Boolean)

    true if the current batch job is a result of an error_handler



105
106
107
# File 'lib/eco/api/session/batch/job.rb', line 105

def error_handler?
  usecase? && usecase.is_a?(Eco::API::Error::Handler)
end

#errors?Boolean

Returns true if there were Server errors, false otherwise.

Returns:

  • (Boolean)

    true if there were Server errors, false otherwise

See Also:



176
177
178
# File 'lib/eco/api/session/batch/job.rb', line 176

def errors?
  status&.errors?
end

#launch(simulate: false) ⇒ Eco::API::Session::Batch::Status

Processes the queue and, unless simulate is true, launches against the server:

  1. pre_processes the queue obtaining the requests:
    • if the entries of queue got pending callbacks (delayed changes), it processes them
    • unless type == :create: if there's a defined api_excluded callback it calls it (see Config::People#api_excluded)
    • transforms the result to a Eco::API::Organization::People object
    • if there are api policies defined, it passes the entries through them in order (see Config#policies)
      • this step is skipped if the option -skip-api-policies was used in the command line
    • at this point all the transformations have taken place...
    • only include the entries that, after all above, still hold pending changes (!as_update.empty?) to be launched as update
  2. pre launch checks against the requests:
    • it generates stats (Eco::API::Session::Batch::RequestStats) out of the requests
    • if there is a batch policy declared for the current job type, it checks compliance against stats (see Policies),
      • a non-compliant batch will stop the current session by raising an Exception
      • this setp is skipped if the option -skip-batch-policy was used in the command line
  3. if we are not in dry-run (or simulate), it:
    • backs up the raw queries (requests) launched to the Server, if we are not in dry-run (or simulate)
    • launches the batch request against the Server (see Eco::API::Session::Batch#launch)
    • links the resulting batch status to this Batch::Job (see Status)
    • prints any errors replied by the Server
  4. the post launch kicks in, and:
    • for success requests, it consolidates the associated entries (see Ecoportal::API::V1::Person#consolidate!)
    • launches specific error handlers, if there were errors from the Server as a result of the batch.launch, and there are Error::Handlers defined


217
218
219
220
221
222
223
224
225
226
227
228
229
230
231
232
233
234
235
236
237
238
239
240
241
242
243
244
245
246
247
248
249
250
251
252
# File 'lib/eco/api/session/batch/job.rb', line 217

def launch(simulate: false) # rubocop:disable Metrics/AbcSize
  pqueue    = processed_queue
  @requests = as_update(pqueue)
  pre_checks(requests, simulate: simulate)

  if simulate
    if options.dig(:requests, :backup)
      req_backup = as_update(pqueue, add_feedback: false)
      backup_update(req_backup, simulate: simulate)
    end
  elsif !pqueue.empty?
    req_backup = as_update(pqueue, add_feedback: false)
    backup_update(req_backup)

    log(:debug) {
      "Job ('#{name}':#{type}): going to launch batch against #{pqueue.count} entries"
    }

    session.batch.launch(pqueue, method: type).tap do |job_status|
      @status     = job_status
      status.root = self
      status.errors.print
    end
  end

  unless requests.empty? || !simulate
    msg  = "--- simulate mode (dry-run) --  job '#{name}' "
    msg << "-- this would have launched #{type.to_s.upcase}"
    log(:info) { msg }
  end

  post_launch(queue: pqueue, simulate: simulate)
  @pending = false

  status
end

#optionsHash

Returns options the root usecase is run with.

Returns:

  • (Hash)

    options the root usecase is run with



115
116
117
# File 'lib/eco/api/session/batch/job.rb', line 115

def options
  usecase?? usecase.options : {}
end

#pending?Boolean

Returns has been this batch job launched?.

Returns:

  • (Boolean)

    has been this batch job launched?



145
146
147
# File 'lib/eco/api/session/batch/job.rb', line 145

def pending?
  @pending
end

#people(input = @queue) ⇒ Eco::API::Organization::People

Note:

if input is not provided, it will use queue

Helper/shortcut to obtain a people object out of input



183
184
185
# File 'lib/eco/api/session/batch/job.rb', line 183

def people(input = @queue)
  Eco::API::Organization::People.new(input)
end

#request_stats(requests = nil) ⇒ Object



170
171
172
# File 'lib/eco/api/session/batch/job.rb', line 170

def request_stats(requests = nil)
  feedback.request_stats(requests || self.requests)
end

#requestsEnumbrable<Hash>

Note:

it requires launch to be firstly invoked

Returns the last requests that the queue will generate.

Returns:

  • (Enumbrable<Hash>)

    the last requests that the queue will generate

Raises:

  • (Exception)

    if 'launch' has not firstly invoked



162
163
164
165
166
167
# File 'lib/eco/api/session/batch/job.rb', line 162

def requests
  msg = "Method missuse. Firstly 'launch' should be invoked"
  raise msg unless instance_variable_defined?(:@requests)

  @requests
end

#resetObject



73
74
75
76
77
78
79
# File 'lib/eco/api/session/batch/job.rb', line 73

def reset
  @queue      = []
  @queue_hash = {}
  @callbacks  = {}
  @pending    = true
  @status     = nil
end

#subjobsEco::API::Session::Batch::Jobs

Returns group of subjobs of this Batch::Job.

Returns:



97
98
99
100
101
102
# File 'lib/eco/api/session/batch/job.rb', line 97

def subjobs
  @subjobs ||= Eco::API::Session::Batch::Jobs.new(
    enviro,
    name: "childs-of:#{name}"
  )
end

#summaryString

Note:

if launch was not invoked, it specifies so

Provides a text summary of the current status including:

  1. stats of the changes introduced by the job in the different parts of the person model
  2. if the job is compliant with the batch policy
  3. error messages in case they were errors from the server

Returns:

  • (String)

    the summary



260
261
262
263
264
265
266
267
268
269
270
271
272
273
274
# File 'lib/eco/api/session/batch/job.rb', line 260

def summary
  [].tap do |msg|
    msg << "PENDING Job -------->\n" if pending?
    ensure_requests!
    msg << feedback.generate(requests, only_stats: true)

    if batch_policy && !batch_policy.compliant?(request_stats)
      msg << 'Batch Policy Uncompliance:'
      msg << batch_policy.uncompliance(request_stats)
    end

    msg << status.errors.message if status
    msg << subjobs_summary
  end.join("\n")
end

#usecase?Boolean

Returns was this batch job generated by a usecase? (Eco::API::UseCases::UseCase).

Returns:

  • (Boolean)

    was this batch job generated by a usecase? (Eco::API::UseCases::UseCase)



110
111
112
# File 'lib/eco/api/session/batch/job.rb', line 110

def usecase?
  !!usecase
end