startback-jobs 0.15.4 → 0.15.5

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: b9f52906536b68aca921b237f543d8c318dccb9fbb8f8529452a1bc110de69f4
4
- data.tar.gz: ae92e6c795a93c467b9b3ecf4372294aacc40fd5437e7d9e0ab39531f4c632b4
3
+ metadata.gz: dea8bb6951ccc73ca5eafdfea151129905ab26dfea75d1ea9dfc824204a6131f
4
+ data.tar.gz: 8a2e8ae265595a674bd8c2afcf43619df1bba338a0cde5900fe333ecee874013
5
5
  SHA512:
6
- metadata.gz: 5e17019a71d938b84e1a81e21c073cf238df721d05443a02304e1ed70f2030a237cfbeca009f6083b73161546cce80857f94a7fd4142db5f8b3e67107a6f7b7c
7
- data.tar.gz: 7f8b2d724578961575ed3ab73bb53cfd47e08c211dfa80314ae408e316aea583967d88c8b6e0083eab60a768b793b32daa78e856b6a4e71d605e9e94c741ae6f
6
+ metadata.gz: 627a7f6a0ddb28fe9a08120fbd2cf8240a29811fc8ae35151d65501a3f563c82fb265c18ad0f22d514ad5f8c6e2cd6ffb5c51c3ac6d212271ab3cdc4d725a126
7
+ data.tar.gz: 33362ef7e67b2f176f489e40aeb6a0b62ef90b231fb5bf079cef4ab243e55e04ebf72916dc2b7ba5801791a048b5c56382661ea229fa103abd6d6a2893d5007b
@@ -18,6 +18,14 @@ module Startback
18
18
  !ready?
19
19
  end
20
20
 
21
+ def failed?
22
+ !!self[:hasFailed]
23
+ end
24
+
25
+ def succeeded?
26
+ !failed?
27
+ end
28
+
21
29
  def expired?
22
30
  self.expiredAt && self.expiredAt < Time.now
23
31
  end
@@ -15,6 +15,7 @@ module Startback
15
15
  strategy: 'NotReady',
16
16
  strategyOptions: {},
17
17
  expiresAt: nil,
18
+ hasFailed: false,
18
19
  refreshFreq: nil,
19
20
  refreshedAt: nil,
20
21
  consumeMax: nil,
@@ -14,12 +14,16 @@ module Startback
14
14
  job_class = ::Kernel.const_get(@job.op_class)
15
15
  job_input = @job.op_input
16
16
 
17
- op_result = with_context(job_context) do
18
- run job_class.new(job_input)
17
+ has_failed, op_result = with_context(job_context) do
18
+ op_result = run job_class.new(job_input)
19
+ [false, op_result]
20
+ rescue => err
21
+ [true, error_to_result(err) ]
19
22
  end
20
23
 
21
24
  services.update_job!(input, {
22
25
  opResult: op_result,
26
+ hasFailed: has_failed,
23
27
  isReady: true,
24
28
  strategy: 'Embedded',
25
29
  })
@@ -27,6 +31,14 @@ module Startback
27
31
  op_result
28
32
  end
29
33
 
34
+ def error_to_result(err)
35
+ {
36
+ errClass: err.class.name.to_s,
37
+ message: err.message,
38
+ backtrace: err.backtrace
39
+ }
40
+ end
41
+
30
42
  emits(Event::JobRan) do
31
43
  { id: @job.id }
32
44
  end
@@ -4,12 +4,25 @@ module Startback
4
4
  class JobResult
5
5
  class Embedded < JobResult
6
6
 
7
+ # Non HTTP-standard special success code to
8
+ # indicate a job failure...
9
+ FAILURE_STATUS_CODE = 272
10
+
7
11
  def api_serve(api)
8
- [
9
- 200,
10
- {"Content-Type" => "application/json"},
11
- [job.opResult.to_json]
12
- ]
12
+ if job.failed?
13
+ payload = job.opResult.delete_if{|k| k == :backtrace }
14
+ [
15
+ FAILURE_STATUS_CODE,
16
+ {"Content-Type" => "application/json"},
17
+ [payload.to_json]
18
+ ]
19
+ else
20
+ [
21
+ 200,
22
+ {"Content-Type" => "application/json"},
23
+ [job.opResult.to_json]
24
+ ]
25
+ end
13
26
  end
14
27
 
15
28
  end # class Embedded
@@ -11,10 +11,10 @@ module Startback
11
11
  attr_reader :job
12
12
 
13
13
  def self.for(job)
14
- unless job.is_ready?
15
- JobResult::NotReady.new(job)
16
- else
14
+ if job.is_ready?
17
15
  JobResult.const_get(job.strategy).new(job)
16
+ else
17
+ JobResult::NotReady.new(job)
18
18
  end
19
19
  end
20
20
 
@@ -11,21 +11,22 @@ Job.Ref = {
11
11
  Job.Strategy = String(s | %w{Embedded NotReady Redirect}.include? s )
12
12
 
13
13
  Job.Full = {
14
- id : String
15
- opClass : ClassName
16
- opInput : DumpableHash
17
- opContext : DumpableHash
18
- opResult : .
19
- isReady : Boolean
20
- strategy : Job.Strategy
21
- strategyOptions : DumpableHash
22
- expiresAt : DateTime|Time|Nil
23
- refreshFreq : String|Nil
24
- refreshedAt : DateTime|Time|Nil
25
- consumeMax : Integer|Nil
26
- consumeCount : Integer|Nil
27
- createdAt : DateTime|Time|Nil
28
- createdBy : String|Nil
14
+ id : String
15
+ opClass : ClassName
16
+ opInput : DumpableHash
17
+ opContext : DumpableHash
18
+ opResult : .
19
+ isReady : Boolean
20
+ hasFailed :? Boolean
21
+ strategy : Job.Strategy
22
+ strategyOptions : DumpableHash
23
+ expiresAt : DateTime|Time|Nil
24
+ refreshFreq : String|Nil
25
+ refreshedAt : DateTime|Time|Nil
26
+ consumeMax : Integer|Nil
27
+ consumeCount : Integer|Nil
28
+ createdAt : DateTime|Time|Nil
29
+ createdBy : String|Nil
29
30
  }
30
31
 
31
32
  Job.CreationRequest = {
data/spec/spec_helper.rb CHANGED
@@ -15,10 +15,11 @@ RSpec.configure do |c|
15
15
  id: 'abcdef',
16
16
  isReady: false,
17
17
  opClass: 'CowSay',
18
- opInput: { 'message' => 'Hello !!' },
18
+ opInput: { 'message' => 'Hello !!', 'crash' => false },
19
19
  opContext: {},
20
20
  opResult: nil,
21
21
  strategy: 'NotReady',
22
+ hasFailed: false,
22
23
  strategyOptions: {},
23
24
  expiresAt: nil,
24
25
  refreshFreq: nil,
@@ -37,6 +38,7 @@ class CowSay < Startback::Operation
37
38
  end
38
39
 
39
40
  def call
41
+ raise Startback::Errors::InternalServerError, "Something bad happened" if input.crash
40
42
  input.message
41
43
  end
42
44
  end
@@ -64,10 +64,11 @@ module Startback
64
64
  end
65
65
  end
66
66
 
67
- context 'when the job is ready' do
67
+ context 'when the job is ready and successful' do
68
68
  let(:override) do
69
69
  {
70
70
  isReady: true,
71
+ hasFailed: false,
71
72
  opResult: { "foo" => 'Hello!!' },
72
73
  strategy: 'Embedded'
73
74
  }
@@ -80,6 +81,30 @@ module Startback
80
81
  end
81
82
  end
82
83
 
84
+ context 'when the job failed' do
85
+ let(:override) do
86
+ {
87
+ isReady: true,
88
+ hasFailed: true,
89
+ opResult: {
90
+ errClass: 'AClass',
91
+ message: 'Something bad happened',
92
+ backtrace: ['private information'],
93
+ },
94
+ strategy: 'Embedded'
95
+ }
96
+ end
97
+
98
+ it 'works fine' do
99
+ res = subject
100
+ expect(res.status).to eql(272)
101
+ decoded = JSON.parse(res.body)
102
+ expect(decoded.keys).to eql(['errClass', 'message'])
103
+ expect(decoded['errClass']).to eql('AClass')
104
+ expect(decoded['message']).to eql('Something bad happened')
105
+ end
106
+ end
107
+
83
108
  context 'when the job is ready and has to redirect' do
84
109
  let(:override) do
85
110
  {
@@ -17,6 +17,18 @@ module Startback
17
17
  expect(job[:id]).to eql('abcdef')
18
18
  expect(job.ready?).to eql(false)
19
19
  end
20
+
21
+ it 'recognizes failed jobs' do
22
+ job = Job.full(a_job_data.merge(hasFailed: true))
23
+ expect(job.id).to eql('abcdef')
24
+ expect(job.failed?).to eql(true)
25
+ end
26
+
27
+ it 'stays compatible with jobs without the hasFailed flag' do
28
+ job = Job.full(a_job_data.delete_if{|k| k == :hasFailed })
29
+ expect(job.id).to eql('abcdef')
30
+ expect(job.failed?).to eql(false)
31
+ end
20
32
  end
21
33
  end
22
34
  end
@@ -4,10 +4,6 @@ module Startback
4
4
  module Jobs
5
5
  describe RunJob do
6
6
 
7
- let(:job_data) do
8
- a_job_data
9
- end
10
-
11
7
  let(:jobs_relvar) do
12
8
  Bmg.mutable([job_data])
13
9
  end
@@ -22,16 +18,42 @@ module Startback
22
18
  }).call
23
19
  end
24
20
 
25
- it 'runs the job' do
26
- expect(subject).to eql('Hello !!')
21
+ describe 'When job runs successfuly' do
22
+
23
+ let(:job_data) do
24
+ a_job_data
25
+ end
26
+
27
+ it 'runs the job' do
28
+ expect(subject).to eql('Hello !!')
29
+ end
30
+
31
+ it 'updates the job' do
32
+ subject
33
+ job_info = jobs_relvar.one
34
+ expect(job_info[:opResult]).to eql('Hello !!')
35
+ expect(job_info[:isReady]).to eql(true)
36
+ end
27
37
  end
28
38
 
29
- it 'updates the job' do
30
- subject
31
- job_info = jobs_relvar.one
32
- expect(job_info[:opResult]).to eql('Hello !!')
33
- expect(job_info[:isReady]).to eql(true)
39
+ describe 'When job fails' do
40
+
41
+ let(:job_data) do
42
+ a_job_data({
43
+ opInput: { 'crash' => true },
44
+ })
45
+ end
46
+
47
+ it 'updates the job' do
48
+ subject
49
+ job_info = jobs_relvar.one
50
+ expect(job_info[:isReady]).to eql(true)
51
+ expect(job_info[:opResult][:errClass]).to eql('Startback::Errors::InternalServerError')
52
+ expect(job_info[:opResult][:message]).to eql('Something bad happened')
53
+ expect(job_info[:opResult][:backtrace]).to be_a(Array)
54
+ end
34
55
  end
56
+
35
57
  end
36
58
  end
37
59
  end
metadata CHANGED
@@ -1,14 +1,14 @@
1
1
  --- !ruby/object:Gem::Specification
2
2
  name: startback-jobs
3
3
  version: !ruby/object:Gem::Version
4
- version: 0.15.4
4
+ version: 0.15.5
5
5
  platform: ruby
6
6
  authors:
7
7
  - Bernard Lambeau
8
8
  autorequire:
9
9
  bindir: bin
10
10
  cert_chain: []
11
- date: 2022-10-13 00:00:00.000000000 Z
11
+ date: 2023-01-11 00:00:00.000000000 Z
12
12
  dependencies:
13
13
  - !ruby/object:Gem::Dependency
14
14
  name: rspec
@@ -118,14 +118,14 @@ dependencies:
118
118
  requirements:
119
119
  - - '='
120
120
  - !ruby/object:Gem::Version
121
- version: 0.15.4
121
+ version: 0.15.5
122
122
  type: :runtime
123
123
  prerelease: false
124
124
  version_requirements: !ruby/object:Gem::Requirement
125
125
  requirements:
126
126
  - - '='
127
127
  - !ruby/object:Gem::Version
128
- version: 0.15.4
128
+ version: 0.15.5
129
129
  description: Asynchronous jobs on top of the Startback framework
130
130
  email: blambeau@gmail.com
131
131
  executables: []
@@ -181,7 +181,7 @@ required_rubygems_version: !ruby/object:Gem::Requirement
181
181
  - !ruby/object:Gem::Version
182
182
  version: '0'
183
183
  requirements: []
184
- rubygems_version: 3.1.2
184
+ rubygems_version: 3.3.5
185
185
  signing_key:
186
186
  specification_version: 4
187
187
  summary: Asynchronous jobs on top of Startback