mirror of
https://github.com/grassrootseconomics/cic-custodial.git
synced 2024-11-23 06:36:46 +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)
|
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(
|
return strings.ReplaceAll(strings.ToLower(
|
||||||
strings.TrimPrefix(s, "")), "_", ".")
|
strings.TrimPrefix(s, "CUSTODIAL_")), "__", ".")
|
||||||
}), nil); err != nil {
|
}), nil); err != nil {
|
||||||
lo.Fatal("Could not override config from env vars", "error", err)
|
lo.Fatal("Could not override config from env vars", "error", err)
|
||||||
}
|
}
|
||||||
|
|
||||||
|
ko.Print()
|
||||||
|
|
||||||
return ko
|
return ko
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -180,6 +182,7 @@ func initPostgresStore(postgresPool *pgxpool.Pool, queries *queries.Queries) sto
|
|||||||
// Init JetStream context for tasker events.
|
// Init JetStream context for tasker events.
|
||||||
func initJetStream() (*events.JetStream, error) {
|
func initJetStream() (*events.JetStream, error) {
|
||||||
jsEmitter, err := events.NewJetStreamEventEmitter(events.JetStreamOpts{
|
jsEmitter, err := events.NewJetStreamEventEmitter(events.JetStreamOpts{
|
||||||
|
Logg: lo,
|
||||||
ServerUrl: ko.MustString("jetstream.endpoint"),
|
ServerUrl: ko.MustString("jetstream.endpoint"),
|
||||||
PersistDuration: time.Duration(ko.MustInt("jetstream.persist_duration_hrs")) * time.Hour,
|
PersistDuration: time.Duration(ko.MustInt("jetstream.persist_duration_hrs")) * time.Hour,
|
||||||
DedupDuration: time.Duration(ko.MustInt("jetstream.dedup_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()
|
<-ctx.Done()
|
||||||
|
|
||||||
lo.Info("main: stopping tasker")
|
lo.Info("main: stopping tasker")
|
||||||
|
@ -7,6 +7,7 @@ metrics = true
|
|||||||
[chain]
|
[chain]
|
||||||
rpc_endpoint = ""
|
rpc_endpoint = ""
|
||||||
testnet = true
|
testnet = true
|
||||||
|
devnet = false
|
||||||
|
|
||||||
[system]
|
[system]
|
||||||
# System default values
|
# System default values
|
||||||
|
@ -23,14 +23,14 @@ const (
|
|||||||
)
|
)
|
||||||
|
|
||||||
type JetStreamOpts struct {
|
type JetStreamOpts struct {
|
||||||
Logg logf.Logger
|
Logg logf.Logger
|
||||||
ServerUrl string
|
ServerUrl string
|
||||||
PersistDuration time.Duration
|
PersistDuration time.Duration
|
||||||
DedupDuration time.Duration
|
DedupDuration time.Duration
|
||||||
}
|
}
|
||||||
|
|
||||||
type JetStream struct {
|
type JetStream struct {
|
||||||
logg logf.Logger
|
logg logf.Logger
|
||||||
jsCtx nats.JetStreamContext
|
jsCtx nats.JetStreamContext
|
||||||
natsConn *nats.Conn
|
natsConn *nats.Conn
|
||||||
}
|
}
|
||||||
@ -62,6 +62,7 @@ func NewJetStreamEventEmitter(o JetStreamOpts) (*JetStream, error) {
|
|||||||
}
|
}
|
||||||
|
|
||||||
return &JetStream{
|
return &JetStream{
|
||||||
|
logg: o.Logg,
|
||||||
jsCtx: js,
|
jsCtx: js,
|
||||||
natsConn: natsConn,
|
natsConn: natsConn,
|
||||||
}, nil
|
}, nil
|
||||||
|
@ -2,21 +2,29 @@ package events
|
|||||||
|
|
||||||
import (
|
import (
|
||||||
"context"
|
"context"
|
||||||
|
"encoding/json"
|
||||||
"errors"
|
"errors"
|
||||||
"time"
|
|
||||||
|
|
||||||
"github.com/grassrootseconomics/cic-custodial/internal/store"
|
"github.com/grassrootseconomics/cic-custodial/internal/store"
|
||||||
"github.com/nats-io/nats.go"
|
"github.com/nats-io/nats.go"
|
||||||
)
|
)
|
||||||
|
|
||||||
const (
|
const (
|
||||||
backOffTimer = 2 * time.Second
|
durableId = "cic-custodial"
|
||||||
durableId = "cic-custodial"
|
pullStream = "CHAIN"
|
||||||
pullStream = "CHAIN"
|
pullSubject = "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{
|
subOpts := []nats.SubOpt{
|
||||||
nats.ManualAck(),
|
nats.ManualAck(),
|
||||||
nats.Bind(pullStream, durableId),
|
nats.Bind(pullStream, durableId),
|
||||||
@ -31,23 +39,34 @@ func (js *JetStream) ChainSubscription(ctx context.Context, store store.Store) e
|
|||||||
select {
|
select {
|
||||||
case <-ctx.Done():
|
case <-ctx.Done():
|
||||||
js.logg.Info("jetstream chain sub: shutdown signal received")
|
js.logg.Info("jetstream chain sub: shutdown signal received")
|
||||||
|
js.Close()
|
||||||
return nil
|
return nil
|
||||||
default:
|
default:
|
||||||
events, err := natsSub.Fetch(1)
|
events, err := natsSub.Fetch(1)
|
||||||
if err != nil {
|
if err != nil {
|
||||||
if errors.Is(err, nats.ErrTimeout) {
|
if errors.Is(err, nats.ErrTimeout) {
|
||||||
// Supressed retry
|
|
||||||
js.logg.Error("jetstream chain sub: fetch NATS timeout", "error", err)
|
|
||||||
time.Sleep(backOffTimer)
|
|
||||||
continue
|
continue
|
||||||
} else {
|
} else {
|
||||||
js.logg.Error("jetstream chain sub: fetch other error", "error", err)
|
js.logg.Error("jetstream chain sub: fetch other error", "error", err)
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
if len(events) > 0 {
|
if len(events) == 0 {
|
||||||
// TODO: Unmarshal
|
continue
|
||||||
// TODO: UpdateOtxStatus
|
|
||||||
}
|
}
|
||||||
|
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 (
|
import (
|
||||||
"context"
|
"context"
|
||||||
|
|
||||||
"github.com/grassrootseconomics/cic-custodial/pkg/enum"
|
|
||||||
)
|
)
|
||||||
|
|
||||||
func (s *PostgresStore) CreateDispatchStatus(ctx context.Context, dispatch DispatchStatus) error {
|
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
|
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"
|
"time"
|
||||||
|
|
||||||
"github.com/georgysavva/scany/v2/pgxscan"
|
"github.com/georgysavva/scany/v2/pgxscan"
|
||||||
|
"github.com/grassrootseconomics/cic-custodial/pkg/enum"
|
||||||
)
|
)
|
||||||
|
|
||||||
type TxStatus struct {
|
type TxStatus struct {
|
||||||
@ -58,6 +59,24 @@ func (s *PostgresStore) GetTxStatusByTrackingId(ctx context.Context, trackingId
|
|||||||
return txs, nil
|
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
|
return nil
|
||||||
}
|
}
|
||||||
|
@ -7,6 +7,16 @@ import (
|
|||||||
)
|
)
|
||||||
|
|
||||||
type (
|
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 {
|
OTX struct {
|
||||||
TrackingId string
|
TrackingId string
|
||||||
Type enum.OtxType
|
Type enum.OtxType
|
||||||
@ -29,6 +39,6 @@ type (
|
|||||||
CreateOtx(ctx context.Context, otx OTX) (id uint, err error)
|
CreateOtx(ctx context.Context, otx OTX) (id uint, err error)
|
||||||
CreateDispatchStatus(ctx context.Context, dispatch DispatchStatus) error
|
CreateDispatchStatus(ctx context.Context, dispatch DispatchStatus) error
|
||||||
GetTxStatusByTrackingId(ctx context.Context, trackingId string) ([]*TxStatus, 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