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

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

Class Attribute Summary collapse

Instance Attribute Summary collapse

Attributes inherited from Common::Session::BaseSession

#api, #config, #environment, #file_manager, #logger, #session

Class Method Summary collapse

Instance Method Summary collapse

Methods inherited from Common::Session::BaseSession

#enviro=, #fatal, #fm, #mailer, #mailer?, #s3uploader, #s3uploader?, #sftp, #sftp?

Constructor Details

#initialize(e, name:, type:, sets:, usecase: nil) ⇒ Job

Returns a new instance of Job.

Parameters:

  • e (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.



37
38
39
40
41
42
43
44
45
46
47
48
49
50
# File 'lib/eco/api/session/batch/job.rb', line 37

def initialize(e, name:, type:, sets:, usecase: nil)
  raise "A name is required to refer a job. Given: #{name}" if !name
  raise "Type should be one of #{self.class.types}. Given: #{type}"    unless self.class.valid_type?(type)
  raise "Sets should be some of #{self.class.sets}. Given: #{sets}"    unless self.class.valid_sets?(sets)
  raise "usecase must be a Eco::API::UseCases::UseCase object. Given: #{usecase.class}" if usecase && !usecase.is_a?(Eco::API::UseCases::UseCase)
  super(e)

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

Class Attribute Details

.setsObject (readonly)

Returns the value of attribute sets.



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

def sets
  @sets
end

.typesObject (readonly)

Returns the value of attribute types.



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

def types
  @types
end

Instance Attribute Details

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

helper class for feedback and end-user decision making

Returns:



11
12
13
# File 'lib/eco/api/session/batch/job.rb', line 11

def feedback
  @feedback
end

#nameString (readonly)

the name of this batch job

Returns:

  • (String)

    the current value of name



11
12
13
# File 'lib/eco/api/session/batch/job.rb', line 11

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



11
12
13
# File 'lib/eco/api/session/batch/job.rb', line 11

def sets
  @sets
end

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

if launched: the status of the batch

Returns:



11
12
13
# File 'lib/eco/api/session/batch/job.rb', line 11

def status
  @status
end

#typeSymbol (readonly)

a valid batch operation

Returns:

  • (Symbol)

    the current value of type



11
12
13
# File 'lib/eco/api/session/batch/job.rb', line 11

def type
  @type
end

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

when provided: usecase that generated this batch job

Returns:



11
12
13
# File 'lib/eco/api/session/batch/job.rb', line 11

def usecase
  @usecase
end

Class Method Details

.valid_sets?(value) ⇒ Boolean

Returns:

  • (Boolean)


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

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

.valid_type?(value) ⇒ Boolean

Returns:

  • (Boolean)


18
19
20
# File 'lib/eco/api/session/batch/job.rb', line 18

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, Enumberable<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:

  • param (Person)

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

Returns:



101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
# File 'lib/eco/api/session/batch/job.rb', line 101

def add(entry, unique: true, &block)
  case entry
  when Enumerable
    entry.each {|e| add(e, unique: unique, &block)}
  else
    unless !entry
      unless unique && @queue_hash.key?(entry)
        @queue_hash[entry] = true
        @queue.push(entry)
        @callbacks[entry]  = Proc.new if block_given?
      end
    end
  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



65
66
67
# File 'lib/eco/api/session/batch/job.rb', line 65

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

#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



81
82
83
# File 'lib/eco/api/session/batch/job.rb', line 81

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:



137
138
139
# File 'lib/eco/api/session/batch/job.rb', line 137

def errors?
  status && 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


171
172
173
174
175
176
177
178
179
180
181
182
183
184
185
186
187
188
189
190
191
192
193
194
# File 'lib/eco/api/session/batch/job.rb', line 171

def launch(simulate: false)
  pqueue    = processed_queue
  @requests = pqueue.map {|e| as_update(e)}
  pre_checks(requests, simulate: simulate)

  unless simulate
    if pqueue.length > 0
      backup_update(requests)
      session.batch.launch(pqueue, method: type).tap do |job_status|
        @status     = job_status
        status.root = self
        status.errors.print
      end
    end
  end

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

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

#optionsHash

Returns options the root usecase is run with.

Returns:

  • (Hash)

    options the root usecase is run with



91
92
93
# File 'lib/eco/api/session/batch/job.rb', line 91

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

#pending?Boolean

Returns has been this batch job launched?.

Returns:

  • (Boolean)

    has been this batch job launched?



118
119
120
# File 'lib/eco/api/session/batch/job.rb', line 118

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



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

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

#request_stats(requests = nil) ⇒ Object



131
132
133
# File 'lib/eco/api/session/batch/job.rb', line 131

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



125
126
127
128
# File 'lib/eco/api/session/batch/job.rb', line 125

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

#resetObject



52
53
54
55
56
57
58
# File 'lib/eco/api/session/batch/job.rb', line 52

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:



70
71
72
# File 'lib/eco/api/session/batch/job.rb', line 70

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

#subjobs_add(name = "ad-hoc:job-from:#{self.name}", usecase: self.usecase, &block) ⇒ Object



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

def subjobs_add(name = "ad-hoc:job-from:#{self.name}", usecase: self.usecase, &block)
  dup(name, usecase: usecase).tap do |subjob|
    subjobs.add(subjob, &block)
  end
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



202
203
204
205
206
207
208
209
210
211
212
213
214
215
216
# File 'lib/eco/api/session/batch/job.rb', line 202

def summary
  [].tap do |msg|
    if pending?
      msg << "PENDING - Batch #{type.to_s.upcase} - job '#{name}' - length: #{@queue.length}"
    else
      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 unless !status
    end
  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)



86
87
88
# File 'lib/eco/api/session/batch/job.rb', line 86

def usecase?
  !!usecase
end