feedx 0.14.0 → 0.15.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.
checksums.yaml CHANGED
@@ -1,7 +1,7 @@
1
1
  ---
2
2
  SHA256:
3
- metadata.gz: c1978c7def650e2a2630e36fc0bfc59b9eb66c5ead0f7dda9cc83e773a85c1d8
4
- data.tar.gz: 548208072baf9e6f84a7541df5e8a22a5960982007bce4385c7fa538e0290e94
3
+ metadata.gz: 3586f5580c4f0379b966d324df5dee69f2463ad516842194baf180ee222aad3a
4
+ data.tar.gz: '090b0c6828614705ddefa87d9966ff94ca7a61bab334ad891b2df5850f2100f1'
5
5
  SHA512:
6
- metadata.gz: a5b0be41feeafabbffcbbda6ccc1b12df4d24b8d9a9f03f4b8d04ce2fec7b644b99f15db98e67a79294dca1c3b56c072a67ab20b8cbffaed25ec502e74de9ca2
7
- data.tar.gz: d3434d54accaf281ec5e06e25753de74a052d1386a63badf97ff8bfa8a1426162528d8256cbd288969ef1c348d24cf9358c0827b4c7b1af500c71e5349900b63
6
+ metadata.gz: b35993b35880d79d869fb12d2eed818edc675c0a23ea75ea49af8c488c3ca97bbb71812d50dffbb823ad4a0d437e1108629838c658f30ffe2587358902eb4b5b
7
+ data.tar.gz: 801a0aee9a0899215ab80ba379d8c08956a477cea9179be86dd44e5f140feec5d459e75a230c1d28b0b4b0c2c3719bffacf141abacd02610623c46c47f4a68dc
data/Gemfile.lock CHANGED
@@ -1,7 +1,7 @@
1
1
  PATH
2
2
  remote: .
3
3
  specs:
4
- feedx (0.14.0)
4
+ feedx (0.15.0)
5
5
  bfs (>= 0.8.0)
6
6
 
7
7
  GEM
@@ -55,9 +55,9 @@ GEM
55
55
  rubocop-rake (0.7.1)
56
56
  lint_roller (~> 1.1)
57
57
  rubocop (>= 1.72.1)
58
- rubocop-rspec (3.7.0)
58
+ rubocop-rspec (3.8.0)
59
59
  lint_roller (~> 1.1)
60
- rubocop (~> 1.72, >= 1.72.1)
60
+ rubocop (~> 1.81)
61
61
  ruby-progressbar (1.13.0)
62
62
  unicode-display_width (3.2.0)
63
63
  unicode-emoji (~> 4.1)
data/consumer.go CHANGED
@@ -9,7 +9,7 @@ import (
9
9
  )
10
10
 
11
11
  // ConsumeFunc is a callback invoked by consumers.
12
- type ConsumeFunc func(context.Context, *Reader) error
12
+ type ConsumeFunc func(*Reader) error
13
13
 
14
14
  // Consumer manages data retrieval from a remote feed.
15
15
  // It queries the feed in regular intervals, continuously retrieving new updates.
@@ -106,7 +106,7 @@ func (c *consumer) Consume(ctx context.Context, opt *ReaderOptions, fn ConsumeFu
106
106
  defer reader.Close()
107
107
 
108
108
  // consume feed
109
- if err := fn(ctx, reader); err != nil {
109
+ if err := fn(reader); err != nil {
110
110
  return nil, err
111
111
  }
112
112
 
data/consumer_test.go CHANGED
@@ -1,7 +1,6 @@
1
1
  package feedx_test
2
2
 
3
3
  import (
4
- "context"
5
4
  "reflect"
6
5
  "testing"
7
6
 
@@ -134,7 +133,7 @@ func fixIncrementalConsumer(t *testing.T, version int64) feedx.Consumer {
134
133
  func testConsume(t *testing.T, csm feedx.Consumer, exp *feedx.Status) (msgs []*testdata.MockMessage) {
135
134
  t.Helper()
136
135
 
137
- status, err := csm.Consume(t.Context(), nil, func(ctx context.Context, r *feedx.Reader) (err error) {
136
+ status, err := csm.Consume(t.Context(), nil, func(r *feedx.Reader) (err error) {
138
137
  msgs, err = readMessages(r)
139
138
  return err
140
139
  })
data/example_test.go CHANGED
@@ -43,7 +43,7 @@ func Example() {
43
43
 
44
44
  // consume data
45
45
  var msgs []*message
46
- status, err = csm.Consume(context.TODO(), nil, func(ctx context.Context, r *feedx.Reader) error {
46
+ status, err = csm.Consume(context.TODO(), nil, func(r *feedx.Reader) error {
47
47
  for {
48
48
  var msg message
49
49
  if err := r.Decode(&msg); err != nil {
@@ -81,7 +81,7 @@ func ExampleScheduler_Consume() {
81
81
  csm := feedx.NewConsumerForRemote(obj)
82
82
  defer csm.Close()
83
83
 
84
- job := feedx.Every(time.Hour).
84
+ job, err := feedx.Every(time.Hour).
85
85
  WithContext(ctx).
86
86
  BeforeSync(func(_ int64) bool {
87
87
  fmt.Println("1. Before sync")
@@ -90,10 +90,14 @@ func ExampleScheduler_Consume() {
90
90
  AfterSync(func(_ *feedx.Status, err error) {
91
91
  fmt.Printf("3. After sync - error:%v", err)
92
92
  }).
93
- Consume(csm, func(_ context.Context, _ *feedx.Reader) error {
93
+ Consume(csm, func(_ *feedx.Reader) error {
94
94
  fmt.Println("2. Consuming feed")
95
95
  return nil
96
96
  })
97
+ if err != nil {
98
+ panic(err)
99
+ }
100
+
97
101
  job.Stop()
98
102
 
99
103
  // Output:
@@ -113,7 +117,7 @@ func ExampleScheduler_Produce() {
113
117
  pcr := feedx.NewProducerForRemote(obj)
114
118
  defer pcr.Close()
115
119
 
116
- job := feedx.Every(time.Hour).
120
+ job, err := feedx.Every(time.Hour).
117
121
  WithContext(ctx).
118
122
  BeforeSync(func(_ int64) bool {
119
123
  fmt.Println("2. Before sync")
@@ -130,6 +134,10 @@ func ExampleScheduler_Produce() {
130
134
  fmt.Println("3. Producing feed")
131
135
  return nil
132
136
  })
137
+ if err != nil {
138
+ panic(err)
139
+ }
140
+
133
141
  job.Stop()
134
142
 
135
143
  // Output:
data/feedx.gemspec CHANGED
@@ -1,6 +1,6 @@
1
1
  Gem::Specification.new do |s|
2
2
  s.name = 'feedx'
3
- s.version = '0.14.0'
3
+ s.version = '0.15.0'
4
4
  s.authors = ['Black Square Media Ltd']
5
5
  s.email = ['info@blacksquaremedia.com']
6
6
  s.summary = %(Exchange data between components via feeds)
data/scheduler.go CHANGED
@@ -60,15 +60,16 @@ func (s *Scheduler) WithReaderOptions(opt *ReaderOptions) *Scheduler {
60
60
  }
61
61
 
62
62
  // Consume starts a consumer job.
63
- func (s *Scheduler) Consume(csm Consumer, cfn ConsumeFunc) *CronJob {
64
- return newCronJob(s.ctx, s.interval, func(ctx context.Context) {
63
+ func (s *Scheduler) Consume(csm Consumer, cfn ConsumeFunc) (*CronJob, error) {
64
+ return newCronJob(s.ctx, s.interval, func(ctx context.Context) error {
65
65
  version := csm.Version()
66
66
  if !s.runBeforeHooks(version) {
67
- return
67
+ return nil
68
68
  }
69
69
 
70
70
  status, err := csm.Consume(ctx, s.readerOpt, cfn)
71
71
  s.runAfterHooks(status, err)
72
+ return err
72
73
  })
73
74
  }
74
75
 
@@ -85,36 +86,38 @@ func (s *Scheduler) WithVersionCheck(fn VersionCheck) *Scheduler {
85
86
  }
86
87
 
87
88
  // Produce starts a producer job.
88
- func (s *Scheduler) Produce(pcr *Producer, pfn ProduceFunc) *CronJob {
89
+ func (s *Scheduler) Produce(pcr *Producer, pfn ProduceFunc) (*CronJob, error) {
89
90
  return s.produce(func(ctx context.Context, version int64) (*Status, error) {
90
91
  return pcr.Produce(ctx, version, s.writerOpt, pfn)
91
92
  })
92
93
  }
93
94
 
94
95
  // ProduceIncrementally starts an incremental producer job.
95
- func (s *Scheduler) ProduceIncrementally(pcr *IncrementalProducer, pfn IncrementalProduceFunc) *CronJob {
96
+ func (s *Scheduler) ProduceIncrementally(pcr *IncrementalProducer, pfn IncrementalProduceFunc) (*CronJob, error) {
96
97
  return s.produce(func(ctx context.Context, version int64) (*Status, error) {
97
98
  return pcr.Produce(ctx, version, s.writerOpt, pfn)
98
99
  })
99
100
  }
100
101
 
101
- func (s *Scheduler) produce(fn func(context.Context, int64) (*Status, error)) *CronJob {
102
- return newCronJob(s.ctx, s.interval, func(ctx context.Context) {
102
+ func (s *Scheduler) produce(fn func(context.Context, int64) (*Status, error)) (*CronJob, error) {
103
+ return newCronJob(s.ctx, s.interval, func(ctx context.Context) error {
103
104
  var version int64
104
105
  if s.versionCheck != nil {
105
106
  latest, err := s.versionCheck(s.ctx)
106
107
  if err != nil {
107
- return
108
+ s.runAfterHooks(nil, err)
109
+ return err
108
110
  }
109
111
  version = latest
110
112
  }
111
113
 
112
114
  if !s.runBeforeHooks(version) {
113
- return
115
+ return nil
114
116
  }
115
117
 
116
118
  status, err := fn(ctx, version)
117
119
  s.runAfterHooks(status, err)
120
+ return err
118
121
  })
119
122
  }
120
123
 
@@ -135,22 +138,21 @@ func (s *Scheduler) runAfterHooks(status *Status, err error) {
135
138
 
136
139
  // CronJob runs in regular intervals until it's stopped.
137
140
  type CronJob struct {
138
- ctx context.Context
139
141
  cancel context.CancelFunc
140
142
  interval time.Duration
141
- perform func(context.Context)
143
+ perform func(context.Context) error
142
144
  wait sync.WaitGroup
143
145
  }
144
146
 
145
- func newCronJob(ctx context.Context, interval time.Duration, perform func(context.Context)) *CronJob {
146
- ctx, cancel := context.WithCancel(ctx)
147
-
148
- job := &CronJob{ctx: ctx, cancel: cancel, interval: interval, perform: perform}
149
- job.perform(ctx) // perform immediately
147
+ func newCronJob(ctx context.Context, interval time.Duration, perform func(context.Context) error) (*CronJob, error) {
148
+ if err := perform(ctx); err != nil {
149
+ return nil, err
150
+ }
150
151
 
151
- job.wait.Add(1)
152
- go job.loop()
153
- return job
152
+ ctx, cancel := context.WithCancel(ctx)
153
+ job := &CronJob{cancel: cancel, interval: interval, perform: perform}
154
+ go job.loop(ctx)
155
+ return job, nil
154
156
  }
155
157
 
156
158
  // Stop stops the job and waits until it is complete.
@@ -159,7 +161,8 @@ func (j *CronJob) Stop() {
159
161
  j.wait.Wait()
160
162
  }
161
163
 
162
- func (j *CronJob) loop() {
164
+ func (j *CronJob) loop(ctx context.Context) {
165
+ j.wait.Add(1)
163
166
  defer j.wait.Done()
164
167
 
165
168
  ticker := time.NewTicker(j.interval)
@@ -167,10 +170,10 @@ func (j *CronJob) loop() {
167
170
 
168
171
  for {
169
172
  select {
170
- case <-j.ctx.Done():
173
+ case <-ctx.Done():
171
174
  return
172
175
  case <-ticker.C:
173
- j.perform(j.ctx)
176
+ _ = j.perform(ctx)
174
177
  }
175
178
  }
176
179
  }
data/scheduler_test.go CHANGED
@@ -2,6 +2,7 @@ package feedx_test
2
2
 
3
3
  import (
4
4
  "context"
5
+ "errors"
5
6
  "fmt"
6
7
  "sync/atomic"
7
8
  "testing"
@@ -17,14 +18,23 @@ func TestScheduler(t *testing.T) {
17
18
  numCycles := new(atomic.Int32)
18
19
  numErrors := new(atomic.Int32)
19
20
 
21
+ resetCounters := func() {
22
+ beforeCallbacks.Store(0)
23
+ afterCallbacks.Store(0)
24
+ numCycles.Store(0)
25
+ numErrors.Store(0)
26
+ }
27
+
20
28
  obj := bfs.NewInMemObject("file.json")
21
29
  defer obj.Close()
22
30
 
23
31
  t.Run("produce", func(t *testing.T) {
32
+ resetCounters()
33
+
24
34
  pcr := feedx.NewProducerForRemote(obj)
25
35
  defer pcr.Close()
26
36
 
27
- job := feedx.Every(time.Millisecond).
37
+ job, err := feedx.Every(time.Millisecond).
28
38
  BeforeSync(func(_ int64) bool {
29
39
  beforeCallbacks.Add(1)
30
40
  return true
@@ -45,6 +55,9 @@ func TestScheduler(t *testing.T) {
45
55
  }
46
56
  return nil
47
57
  })
58
+ if err != nil {
59
+ t.Fatal("unexpected error", err)
60
+ }
48
61
 
49
62
  time.Sleep(5 * time.Millisecond)
50
63
  job.Stop()
@@ -71,17 +84,29 @@ func TestScheduler(t *testing.T) {
71
84
  }
72
85
  })
73
86
 
74
- beforeCallbacks.Store(0)
75
- afterCallbacks.Store(0)
76
- numCycles.Store(0)
77
- numErrors.Store(0)
87
+ t.Run("produce may fail", func(t *testing.T) {
88
+ resetCounters()
89
+
90
+ pcr := feedx.NewProducerForRemote(obj)
91
+ defer pcr.Close()
92
+
93
+ exp := fmt.Errorf("failed!")
94
+ _, err := feedx.Every(time.Millisecond).
95
+ Produce(pcr, func(w *feedx.Writer) error {
96
+ return exp
97
+ })
98
+ if !errors.Is(err, exp) {
99
+ t.Errorf("expected %v, got %v", exp, err)
100
+ }
101
+ })
78
102
 
79
103
  t.Run("consume", func(t *testing.T) {
104
+ resetCounters()
80
105
 
81
106
  csm := feedx.NewConsumerForRemote(obj)
82
107
  defer csm.Close()
83
108
 
84
- job := feedx.Every(time.Millisecond).
109
+ job, err := feedx.Every(time.Millisecond).
85
110
  BeforeSync(func(_ int64) bool {
86
111
  beforeCallbacks.Add(1)
87
112
  return true
@@ -93,12 +118,15 @@ func TestScheduler(t *testing.T) {
93
118
  numErrors.Add(1)
94
119
  }
95
120
  }).
96
- Consume(csm, func(ctx context.Context, r *feedx.Reader) error {
121
+ Consume(csm, func(r *feedx.Reader) error {
97
122
  if numCycles.Add(1)%2 == 0 {
98
123
  return fmt.Errorf("failed!")
99
124
  }
100
125
  return nil
101
126
  })
127
+ if err != nil {
128
+ t.Fatal("unexpected error", err)
129
+ }
102
130
 
103
131
  time.Sleep(5 * time.Millisecond)
104
132
  job.Stop()
@@ -125,4 +153,19 @@ func TestScheduler(t *testing.T) {
125
153
  }
126
154
  })
127
155
 
156
+ t.Run("consume may fail", func(t *testing.T) {
157
+ resetCounters()
158
+
159
+ csm := feedx.NewConsumerForRemote(obj)
160
+ defer csm.Close()
161
+
162
+ exp := fmt.Errorf("failed!")
163
+ _, err := feedx.Every(time.Millisecond).
164
+ Consume(csm, func(r *feedx.Reader) error {
165
+ return exp
166
+ })
167
+ if !errors.Is(err, exp) {
168
+ t.Errorf("expected %v, got %v", exp, err)
169
+ }
170
+ })
128
171
  }
metadata CHANGED
@@ -1,7 +1,7 @@
1
1
  --- !ruby/object:Gem::Specification
2
2
  name: feedx
3
3
  version: !ruby/object:Gem::Version
4
- version: 0.14.0
4
+ version: 0.15.0
5
5
  platform: ruby
6
6
  authors:
7
7
  - Black Square Media Ltd