Skip to content

Commit 0c414d7

Browse files
committed
feat(ARCO-291): Ordered callbacks
1 parent 39c062f commit 0c414d7

Some content is hidden

Large Commits have some content hidden by default. Use the searchbox below for content that may be hidden.

42 files changed

+848
-2423
lines changed

cmd/arc/services/callbacker.go

Lines changed: 21 additions & 31 deletions
Original file line numberDiff line numberDiff line change
@@ -31,7 +31,7 @@ import (
3131

3232
"github.com/bitcoin-sv/arc/config"
3333
"github.com/bitcoin-sv/arc/internal/callbacker"
34-
"github.com/bitcoin-sv/arc/internal/callbacker/store"
34+
"github.com/bitcoin-sv/arc/internal/callbacker/send_manager"
3535
"github.com/bitcoin-sv/arc/internal/callbacker/store/postgresql"
3636
"github.com/bitcoin-sv/arc/internal/grpc_opts"
3737
"github.com/bitcoin-sv/arc/internal/message_queue/nats/client/nats_jetstream"
@@ -48,7 +48,6 @@ func StartCallbacker(logger *slog.Logger, arcConfig *config.ArcConfig) (func(),
4848
callbackerStore *postgresql.PostgreSQL
4949
sender *callbacker.CallbackSender
5050
dispatcher *callbacker.CallbackDispatcher
51-
workers *callbacker.BackgroundWorkers
5251
server *callbacker.Server
5352
healthServer *grpc_opts.GrpcServer
5453
mqClient callbacker.MessageQueueClient
@@ -58,7 +57,7 @@ func StartCallbacker(logger *slog.Logger, arcConfig *config.ArcConfig) (func(),
5857

5958
stopFn := func() {
6059
logger.Info("Shutting down callbacker")
61-
dispose(logger, server, workers, dispatcher, sender, callbackerStore, healthServer, processor, mqClient)
60+
dispose(logger, server, dispatcher, sender, callbackerStore, healthServer, processor, mqClient)
6261
logger.Info("Shutdown complete")
6362
}
6463

@@ -73,24 +72,18 @@ func StartCallbacker(logger *slog.Logger, arcConfig *config.ArcConfig) (func(),
7372
return nil, fmt.Errorf("failed to create callback sender: %v", err)
7473
}
7574

76-
sendConfig := callbacker.SendConfig{
77-
Expiration: cfg.Expiration,
78-
Delay: cfg.Delay,
79-
DelayDuration: cfg.DelayDuration,
80-
PauseAfterSingleModeSuccessfulSend: cfg.Pause,
81-
BatchSendInterval: cfg.BatchSendInterval,
82-
}
75+
runNewManager := func(url string) callbacker.SendManagerI {
76+
manager := send_manager.New(url, sender, callbackerStore, logger,
77+
send_manager.WithQueueProcessInterval(cfg.Pause),
78+
send_manager.WithBatchSendInterval(cfg.BatchSendInterval),
79+
send_manager.WithExpiration(cfg.Expiration),
80+
)
81+
manager.Start()
8382

84-
dispatcher = callbacker.NewCallbackDispatcher(sender, callbackerStore, logger, &sendConfig)
85-
workers = callbacker.NewBackgroundWorkers(callbackerStore, dispatcher, logger)
86-
err = workers.DispatchPersistedCallbacks()
87-
if err != nil {
88-
stopFn()
89-
return nil, fmt.Errorf("failed to dispatch previously persisted callbacks: %v", err)
83+
return manager
9084
}
9185

92-
workers.StartCallbackStoreCleanup(cfg.PruneInterval, cfg.PruneOlderThan)
93-
workers.StartFailedCallbacksDispatch(cfg.FailedCallbackCheckInterval)
86+
dispatcher = callbacker.NewCallbackDispatcher(sender, runNewManager)
9487

9588
natsConnection, err := nats_connection.New(arcConfig.MessageQueue.URL, logger)
9689
if err != nil {
@@ -119,6 +112,9 @@ func StartCallbacker(logger *slog.Logger, arcConfig *config.ArcConfig) (func(),
119112
return nil, err
120113
}
121114

115+
processor.StartCallbackStoreCleanup(cfg.PruneInterval, cfg.PruneOlderThan)
116+
processor.DispatchPersistedCallbacks()
117+
122118
err = processor.Start()
123119
if err != nil {
124120
stopFn()
@@ -168,37 +164,31 @@ func newStore(dbConfig *config.DbConfig) (s *postgresql.PostgreSQL, err error) {
168164
return s, err
169165
}
170166

171-
func dispose(l *slog.Logger, server *callbacker.Server, workers *callbacker.BackgroundWorkers,
167+
func dispose(l *slog.Logger, server *callbacker.Server,
172168
dispatcher *callbacker.CallbackDispatcher, sender *callbacker.CallbackSender,
173-
store store.CallbackerStore, healthServer *grpc_opts.GrpcServer, processor *callbacker.Processor, mqClient callbacker.MessageQueueClient) {
169+
store *postgresql.PostgreSQL, healthServer *grpc_opts.GrpcServer, processor *callbacker.Processor, mqClient callbacker.MessageQueueClient) {
174170
// dispose the dependencies in the correct order:
175171
// 1. server - ensure no new callbacks will be received
176-
// 2. background workers - ensure no callbacks from background will be accepted
177-
// 3. dispatcher - ensure all already accepted callbacks are proccessed
172+
// 2. dispatcher - ensure all already accepted callbacks are processed
173+
// 3. processor - remove all URL mappings
178174
// 4. sender - finally, stop the sender as there are no callbacks left to send
179175
// 5. store
180176

181177
if server != nil {
182178
server.GracefulStop()
183179
}
184-
if workers != nil {
185-
workers.GracefulStop()
186-
}
187180
if dispatcher != nil {
188181
dispatcher.GracefulStop()
189182
}
190-
if sender != nil {
191-
sender.GracefulStop()
192-
}
193-
194183
if processor != nil {
195184
processor.GracefulStop()
196185
}
197-
186+
if sender != nil {
187+
sender.GracefulStop()
188+
}
198189
if mqClient != nil {
199190
mqClient.Shutdown()
200191
}
201-
202192
if store != nil {
203193
err := store.Close()
204194
if err != nil {

config/config.go

Lines changed: 9 additions & 12 deletions
Original file line numberDiff line numberDiff line change
@@ -195,16 +195,13 @@ type K8sWatcherConfig struct {
195195
}
196196

197197
type CallbackerConfig struct {
198-
ListenAddr string `mapstructure:"listenAddr"`
199-
DialAddr string `mapstructure:"dialAddr"`
200-
Health *HealthConfig `mapstructure:"health"`
201-
Delay time.Duration `mapstructure:"delay"`
202-
Pause time.Duration `mapstructure:"pause"`
203-
BatchSendInterval time.Duration `mapstructure:"batchSendInterval"`
204-
Db *DbConfig `mapstructure:"db"`
205-
PruneInterval time.Duration `mapstructure:"pruneInterval"`
206-
PruneOlderThan time.Duration `mapstructure:"pruneOlderThan"`
207-
DelayDuration time.Duration `mapstructure:"delayDuration"`
208-
FailedCallbackCheckInterval time.Duration `mapstructure:"failedCallbackCheckInterval"`
209-
Expiration time.Duration `mapstructure:"expiration"`
198+
ListenAddr string `mapstructure:"listenAddr"`
199+
DialAddr string `mapstructure:"dialAddr"`
200+
Health *HealthConfig `mapstructure:"health"`
201+
Pause time.Duration `mapstructure:"pause"`
202+
BatchSendInterval time.Duration `mapstructure:"batchSendInterval"`
203+
PruneOlderThan time.Duration `mapstructure:"pruneOlderThan"`
204+
PruneInterval time.Duration `mapstructure:"pruneInterval"`
205+
Expiration time.Duration `mapstructure:"expiration"`
206+
Db *DbConfig `mapstructure:"db"`
210207
}

config/defaults.go

Lines changed: 6 additions & 8 deletions
Original file line numberDiff line numberDiff line change
@@ -192,14 +192,12 @@ func getCallbackerConfig() *CallbackerConfig {
192192
Health: &HealthConfig{
193193
SeverDialAddr: "localhost:8025",
194194
},
195-
Delay: 0,
196-
Pause: 0,
197-
BatchSendInterval: time.Duration(5 * time.Second),
198-
Db: getDbConfig("callbacker"),
199-
PruneInterval: 24 * time.Hour,
200-
PruneOlderThan: 14 * 24 * time.Hour,
201-
FailedCallbackCheckInterval: time.Minute,
202-
Expiration: 24 * time.Hour,
195+
Pause: 0,
196+
BatchSendInterval: 5 * time.Second,
197+
PruneOlderThan: 14 * 24 * time.Hour,
198+
PruneInterval: 24 * time.Hour,
199+
Expiration: 24 * time.Hour,
200+
Db: getDbConfig("callbacker"),
203201
}
204202
}
205203

config/example_config.yaml

Lines changed: 4 additions & 7 deletions
Original file line numberDiff line numberDiff line change
@@ -156,9 +156,11 @@ callbacker:
156156
dialAddr: localhost:8021 # address for other services to dial callbacker service
157157
health:
158158
serverDialAddr: localhost:8025 # address at which the grpc health server is exposed
159-
delay: 0s # delay before the callback (or batch of callbacks) is actually sent
160-
pause: 0s # pause between sending next callback to the same receiver
159+
pause: 1s # pause between sending next callback to the same receiver - must be greater 0s
161160
batchSendInterval: 5s # interval at witch batched callbacks are send (default 5s)
161+
pruneOlderThan: 336h # age threshold for pruning callbacks (older than this value will be removed)
162+
pruneInterval: 24h # interval at which old or failed callbacks are pruned from the store
163+
expiration: 24h # maximum time a callback can remain unsent before it's put as permanently failed
162164
db:
163165
mode: postgres # db mode indicates which db to use. At the moment only postgres is offered
164166
postgres: # postgres db configuration in case that mode: postgres
@@ -170,8 +172,3 @@ callbacker:
170172
maxIdleConns: 10 # maximum idle connections
171173
maxOpenConns: 80 # maximum open connections
172174
sslMode: disable
173-
pruneInterval: 24h # interval at which old or failed callbacks are pruned from the store
174-
pruneOlderThan: 336h # age threshold for pruning callbacks (older than this value will be removed)
175-
failedCallbackCheckInterval: 1m # interval at which the store is checked for failed callbacks to be re-sent
176-
delayDuration: 5s # we try callbacks a few times with this delay after which if it fails consistently we store them in db
177-
expiration: 24h # maximum time a callback can remain unsent before it's put as permanently failed

docker-compose.yaml

Lines changed: 1 addition & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -180,7 +180,6 @@ services:
180180
condition: service_healthy
181181
migrate-blocktx:
182182
condition: service_completed_successfully
183-
184183
healthcheck:
185184
test: ["CMD", "/bin/grpc_health_probe", "-addr=:8006", "-service=liveness", "-rpc-timeout=5s"]
186185
interval: 10s
@@ -200,7 +199,7 @@ services:
200199
migrate-callbacker:
201200
condition: service_completed_successfully
202201
healthcheck:
203-
test: ["CMD", "/bin/grpc_health_probe", "-addr=:8022", "-service=liveness", "-rpc-timeout=5s"]
202+
test: ["CMD", "/bin/grpc_health_probe", "-addr=:8025", "-service=liveness", "-rpc-timeout=5s"]
204203
interval: 10s
205204
timeout: 5s
206205
retries: 3

internal/blocktx/blocktx_api/blocktx_api.pb.go

Lines changed: 1 addition & 1 deletion
Some generated files are not rendered by default. Learn more about customizing how changed files appear on GitHub.

internal/blocktx/blocktx_api/blocktx_api_grpc.pb.go

Lines changed: 1 addition & 1 deletion
Some generated files are not rendered by default. Learn more about customizing how changed files appear on GitHub.

internal/callbacker/background_workers.go

Lines changed: 0 additions & 160 deletions
This file was deleted.

0 commit comments

Comments
 (0)