mirror of
https://github.com/grassrootseconomics/cic-custodial.git
synced 2024-12-23 18:27:31 +01:00
add: wip jetstream durable consumer
This commit is contained in:
parent
1ddff06502
commit
a1b6cb08d8
@ -48,13 +48,15 @@ func initConfig(configFilePath string) *koanf.Koanf {
|
||||
lo.Fatal("Could not load config file", "error", err)
|
||||
}
|
||||
|
||||
if err := ko.Load(env.Provider("", ".", func(s string) string {
|
||||
if err := ko.Load(env.Provider("CUSTODIAL_", ".", func(s string) string {
|
||||
return strings.ReplaceAll(strings.ToLower(
|
||||
strings.TrimPrefix(s, "")), "_", ".")
|
||||
strings.TrimPrefix(s, "CUSTODIAL_")), "__", ".")
|
||||
}), nil); err != nil {
|
||||
lo.Fatal("Could not override config from env vars", "error", err)
|
||||
}
|
||||
|
||||
ko.Print()
|
||||
|
||||
return ko
|
||||
}
|
||||
|
||||
@ -180,6 +182,7 @@ func initPostgresStore(postgresPool *pgxpool.Pool, queries *queries.Queries) sto
|
||||
// Init JetStream context for tasker events.
|
||||
func initJetStream() (*events.JetStream, error) {
|
||||
jsEmitter, err := events.NewJetStreamEventEmitter(events.JetStreamOpts{
|
||||
Logg: lo,
|
||||
ServerUrl: ko.MustString("jetstream.endpoint"),
|
||||
PersistDuration: time.Duration(ko.MustInt("jetstream.persist_duration_hrs")) * time.Hour,
|
||||
DedupDuration: time.Duration(ko.MustInt("jetstream.dedup_duration_hrs")) * time.Hour,
|
||||
|
@ -128,6 +128,15 @@ func main() {
|
||||
}
|
||||
}()
|
||||
|
||||
wg.Add(1)
|
||||
go func() {
|
||||
defer wg.Done()
|
||||
lo.Info("Starting jetstream subscriber")
|
||||
if err := jsEventEmitter.ChainSubscription(ctx, pgStore); err != nil {
|
||||
lo.Fatal("main: jetstream subscriber", "err", err)
|
||||
}
|
||||
}()
|
||||
|
||||
<-ctx.Done()
|
||||
|
||||
lo.Info("main: stopping tasker")
|
||||
|
@ -7,6 +7,7 @@ metrics = true
|
||||
[chain]
|
||||
rpc_endpoint = ""
|
||||
testnet = true
|
||||
devnet = false
|
||||
|
||||
[system]
|
||||
# System default values
|
||||
|
@ -23,14 +23,14 @@ const (
|
||||
)
|
||||
|
||||
type JetStreamOpts struct {
|
||||
Logg logf.Logger
|
||||
Logg logf.Logger
|
||||
ServerUrl string
|
||||
PersistDuration time.Duration
|
||||
DedupDuration time.Duration
|
||||
}
|
||||
|
||||
type JetStream struct {
|
||||
logg logf.Logger
|
||||
logg logf.Logger
|
||||
jsCtx nats.JetStreamContext
|
||||
natsConn *nats.Conn
|
||||
}
|
||||
@ -62,6 +62,7 @@ func NewJetStreamEventEmitter(o JetStreamOpts) (*JetStream, error) {
|
||||
}
|
||||
|
||||
return &JetStream{
|
||||
logg: o.Logg,
|
||||
jsCtx: js,
|
||||
natsConn: natsConn,
|
||||
}, nil
|
||||
|
@ -2,21 +2,29 @@ package events
|
||||
|
||||
import (
|
||||
"context"
|
||||
"encoding/json"
|
||||
"errors"
|
||||
"time"
|
||||
|
||||
"github.com/grassrootseconomics/cic-custodial/internal/store"
|
||||
"github.com/nats-io/nats.go"
|
||||
)
|
||||
|
||||
const (
|
||||
backOffTimer = 2 * time.Second
|
||||
durableId = "cic-custodial"
|
||||
pullStream = "CHAIN"
|
||||
pullSubject = "CHAIN.*"
|
||||
durableId = "cic-custodial"
|
||||
pullStream = "CHAIN"
|
||||
pullSubject = "CHAIN.*"
|
||||
)
|
||||
|
||||
func (js *JetStream) ChainSubscription(ctx context.Context, store store.Store) error {
|
||||
func (js *JetStream) ChainSubscription(ctx context.Context, pgStore store.Store) error {
|
||||
_, err := js.jsCtx.AddConsumer(pullStream, &nats.ConsumerConfig{
|
||||
Durable: durableId,
|
||||
AckPolicy: nats.AckExplicitPolicy,
|
||||
FilterSubject: pullSubject,
|
||||
})
|
||||
if err != nil {
|
||||
return err
|
||||
}
|
||||
|
||||
subOpts := []nats.SubOpt{
|
||||
nats.ManualAck(),
|
||||
nats.Bind(pullStream, durableId),
|
||||
@ -31,23 +39,34 @@ func (js *JetStream) ChainSubscription(ctx context.Context, store store.Store) e
|
||||
select {
|
||||
case <-ctx.Done():
|
||||
js.logg.Info("jetstream chain sub: shutdown signal received")
|
||||
js.Close()
|
||||
return nil
|
||||
default:
|
||||
events, err := natsSub.Fetch(1)
|
||||
if err != nil {
|
||||
if errors.Is(err, nats.ErrTimeout) {
|
||||
// Supressed retry
|
||||
js.logg.Error("jetstream chain sub: fetch NATS timeout", "error", err)
|
||||
time.Sleep(backOffTimer)
|
||||
continue
|
||||
} else {
|
||||
js.logg.Error("jetstream chain sub: fetch other error", "error", err)
|
||||
}
|
||||
}
|
||||
if len(events) > 0 {
|
||||
// TODO: Unmarshal
|
||||
// TODO: UpdateOtxStatus
|
||||
if len(events) == 0 {
|
||||
continue
|
||||
}
|
||||
var (
|
||||
chainEvent store.MinimalTxInfo
|
||||
)
|
||||
|
||||
if err := json.Unmarshal(events[0].Data, &chainEvent); err != nil {
|
||||
js.logg.Error("jetstream chain sub: json unmarshal fail", "error", err)
|
||||
}
|
||||
|
||||
if err := pgStore.UpdateOtxStatusFromChainEvent(context.Background(), chainEvent); err != nil {
|
||||
events[0].Nak()
|
||||
js.logg.Error("jetstream chain sub: otx marker failed to update state", "error", err)
|
||||
}
|
||||
events[0].Ack()
|
||||
js.logg.Debug("jetstream chain sub: successfully updated status", "tx", chainEvent.TxHash)
|
||||
}
|
||||
|
||||
}
|
||||
|
@ -2,8 +2,6 @@ package store
|
||||
|
||||
import (
|
||||
"context"
|
||||
|
||||
"github.com/grassrootseconomics/cic-custodial/pkg/enum"
|
||||
)
|
||||
|
||||
func (s *PostgresStore) CreateDispatchStatus(ctx context.Context, dispatch DispatchStatus) error {
|
||||
@ -18,17 +16,3 @@ func (s *PostgresStore) CreateDispatchStatus(ctx context.Context, dispatch Dispa
|
||||
|
||||
return nil
|
||||
}
|
||||
|
||||
func (s *PostgresStore) UpdateChainStatus(ctx context.Context, txHash string, status enum.OtxStatus, block uint64) error {
|
||||
if _, err := s.db.Exec(
|
||||
ctx,
|
||||
s.queries.UpdateChainStatus,
|
||||
txHash,
|
||||
status,
|
||||
block,
|
||||
); err != nil {
|
||||
return err
|
||||
}
|
||||
|
||||
return nil
|
||||
}
|
||||
|
@ -5,6 +5,7 @@ import (
|
||||
"time"
|
||||
|
||||
"github.com/georgysavva/scany/v2/pgxscan"
|
||||
"github.com/grassrootseconomics/cic-custodial/pkg/enum"
|
||||
)
|
||||
|
||||
type TxStatus struct {
|
||||
@ -58,6 +59,24 @@ func (s *PostgresStore) GetTxStatusByTrackingId(ctx context.Context, trackingId
|
||||
return txs, nil
|
||||
}
|
||||
|
||||
func (s *PostgresStore) UpdateOtxStatus(ctx context.Context, status string) error {
|
||||
func (s *PostgresStore) UpdateOtxStatusFromChainEvent(ctx context.Context, chainEvent MinimalTxInfo) error {
|
||||
var (
|
||||
status = enum.SUCCESS
|
||||
)
|
||||
|
||||
if !chainEvent.Success {
|
||||
status = enum.REVERTED
|
||||
}
|
||||
|
||||
if _, err := s.db.Exec(
|
||||
ctx,
|
||||
s.queries.UpdateChainStatus,
|
||||
chainEvent.TxHash,
|
||||
status,
|
||||
chainEvent.Block,
|
||||
); err != nil {
|
||||
return err
|
||||
}
|
||||
|
||||
return nil
|
||||
}
|
||||
|
@ -7,6 +7,16 @@ import (
|
||||
)
|
||||
|
||||
type (
|
||||
MinimalTxInfo struct {
|
||||
Block uint64 `json:"block"`
|
||||
From string `json:"from"`
|
||||
To string `json:"to"`
|
||||
ContractAddress string `json:"contractAddress"`
|
||||
Success bool `json:"success"`
|
||||
TxHash string `json:"transactionHash"`
|
||||
TxIndex uint `json:"transactionIndex"`
|
||||
Value uint64 `json:"value"`
|
||||
}
|
||||
OTX struct {
|
||||
TrackingId string
|
||||
Type enum.OtxType
|
||||
@ -29,6 +39,6 @@ type (
|
||||
CreateOtx(ctx context.Context, otx OTX) (id uint, err error)
|
||||
CreateDispatchStatus(ctx context.Context, dispatch DispatchStatus) error
|
||||
GetTxStatusByTrackingId(ctx context.Context, trackingId string) ([]*TxStatus, error)
|
||||
UpdateChainStatus(ctx context.Context, txHash string, status enum.OtxStatus, block uint64) error
|
||||
UpdateOtxStatusFromChainEvent(ctx context.Context, chainEvent MinimalTxInfo) error
|
||||
}
|
||||
)
|
||||
|
Loading…
Reference in New Issue
Block a user