Improve performance in the `tx-tracker` service (#519)
### Description This pull request implements an improvement in the processing logic of the `tx-tracker` service to avoid processing a message more than once.
This commit is contained in:
parent
93e1a72409
commit
0a854b590d
|
@ -693,10 +693,12 @@ func (r *Repository) findOriginTxFromVaa(ctx context.Context, q *GlobalTransacti
|
||||||
// populate the result and return
|
// populate the result and return
|
||||||
originTx := OriginTx{
|
originTx := OriginTx{
|
||||||
Timestamp: &record.Timestamp,
|
Timestamp: &record.Timestamp,
|
||||||
TxHash: record.TxHash,
|
|
||||||
ChainID: record.EmitterChain,
|
ChainID: record.EmitterChain,
|
||||||
Status: string(domain.SourceTxStatusConfirmed),
|
Status: string(domain.SourceTxStatusConfirmed),
|
||||||
}
|
}
|
||||||
|
if record.EmitterChain != sdk.ChainIDSolana && record.EmitterChain != sdk.ChainIDAptos {
|
||||||
|
originTx.TxHash = record.TxHash
|
||||||
|
}
|
||||||
return &originTx, nil
|
return &originTx, nil
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
|
@ -14,7 +14,7 @@ ALGORAND_BASE_URL=https://mainnet-idx.algonode.cloud
|
||||||
ALGORAND_REQUESTS_PER_MINUTE=1
|
ALGORAND_REQUESTS_PER_MINUTE=1
|
||||||
|
|
||||||
APTOS_BASE_URL=https://fullnode.mainnet.aptoslabs.com/v1
|
APTOS_BASE_URL=https://fullnode.mainnet.aptoslabs.com/v1
|
||||||
APTOS_REQUESTS_PER_MINUTE=2
|
APTOS_REQUESTS_PER_MINUTE=1
|
||||||
|
|
||||||
ARBITRUM_BASE_URL=https://rpc.ankr.com/arbitrum
|
ARBITRUM_BASE_URL=https://rpc.ankr.com/arbitrum
|
||||||
ARBITRUM_REQUESTS_PER_MINUTE=1
|
ARBITRUM_REQUESTS_PER_MINUTE=1
|
||||||
|
@ -58,13 +58,13 @@ POLYGON_BASE_URL=https://rpc.ankr.com/polygon
|
||||||
POLYGON_REQUESTS_PER_MINUTE=2
|
POLYGON_REQUESTS_PER_MINUTE=2
|
||||||
|
|
||||||
SOLANA_BASE_URL=https://api.mainnet-beta.solana.com
|
SOLANA_BASE_URL=https://api.mainnet-beta.solana.com
|
||||||
SOLANA_REQUESTS_PER_MINUTE=2
|
SOLANA_REQUESTS_PER_MINUTE=4
|
||||||
|
|
||||||
SUI_BASE_URL=https://fullnode.mainnet.sui.io:443
|
SUI_BASE_URL=https://fullnode.mainnet.sui.io:443
|
||||||
SUI_REQUESTS_PER_MINUTE=1
|
SUI_REQUESTS_PER_MINUTE=1
|
||||||
|
|
||||||
TERRA_BASE_URL=https://columbus-fcd.terra.dev
|
TERRA_BASE_URL=https://columbus-fcd.terra.dev
|
||||||
TERRA_REQUESTS_PER_MINUTE=2
|
TERRA_REQUESTS_PER_MINUTE=4
|
||||||
|
|
||||||
TERRA2_BASE_URL=https://phoenix-lcd.terra.dev
|
TERRA2_BASE_URL=https://phoenix-lcd.terra.dev
|
||||||
TERRA2_REQUESTS_PER_MINUTE=1
|
TERRA2_REQUESTS_PER_MINUTE=1
|
||||||
|
|
|
@ -62,13 +62,13 @@ POLYGON_BASE_URL=https://rpc.ankr.com/polygon
|
||||||
POLYGON_REQUESTS_PER_MINUTE=1
|
POLYGON_REQUESTS_PER_MINUTE=1
|
||||||
|
|
||||||
SOLANA_BASE_URL=https://api.mainnet-beta.solana.com
|
SOLANA_BASE_URL=https://api.mainnet-beta.solana.com
|
||||||
SOLANA_REQUESTS_PER_MINUTE=1
|
SOLANA_REQUESTS_PER_MINUTE=2
|
||||||
|
|
||||||
SUI_BASE_URL=https://fullnode.mainnet.sui.io:443
|
SUI_BASE_URL=https://fullnode.mainnet.sui.io:443
|
||||||
SUI_REQUESTS_PER_MINUTE=1
|
SUI_REQUESTS_PER_MINUTE=1
|
||||||
|
|
||||||
TERRA_BASE_URL=https://columbus-fcd.terra.dev
|
TERRA_BASE_URL=https://columbus-fcd.terra.dev
|
||||||
TERRA_REQUESTS_PER_MINUTE=1
|
TERRA_REQUESTS_PER_MINUTE=2
|
||||||
|
|
||||||
TERRA2_BASE_URL=https://phoenix-lcd.terra.dev
|
TERRA2_BASE_URL=https://phoenix-lcd.terra.dev
|
||||||
TERRA2_REQUESTS_PER_MINUTE=1
|
TERRA2_REQUESTS_PER_MINUTE=1
|
||||||
|
|
|
@ -18,22 +18,22 @@ ALGORAND_BASE_URL=https://mainnet-idx.algonode.cloud
|
||||||
ALGORAND_REQUESTS_PER_MINUTE=2
|
ALGORAND_REQUESTS_PER_MINUTE=2
|
||||||
|
|
||||||
APTOS_BASE_URL=https://fullnode.mainnet.aptoslabs.com/v1
|
APTOS_BASE_URL=https://fullnode.mainnet.aptoslabs.com/v1
|
||||||
APTOS_REQUESTS_PER_MINUTE=2
|
APTOS_REQUESTS_PER_MINUTE=12
|
||||||
|
|
||||||
ARBITRUM_BASE_URL=https://rpc.ankr.com/arbitrum
|
ARBITRUM_BASE_URL=https://rpc.ankr.com/arbitrum
|
||||||
ARBITRUM_REQUESTS_PER_MINUTE=2
|
ARBITRUM_REQUESTS_PER_MINUTE=2
|
||||||
|
|
||||||
AVALANCHE_BASE_URL=https://api.avax.network/ext/bc/C/rpc
|
AVALANCHE_BASE_URL=https://api.avax.network/ext/bc/C/rpc
|
||||||
AVALANCHE_REQUESTS_PER_MINUTE=2
|
AVALANCHE_REQUESTS_PER_MINUTE=8
|
||||||
|
|
||||||
BSC_BASE_URL=https://bsc-dataseed2.defibit.io
|
BSC_BASE_URL=https://bsc-dataseed2.defibit.io
|
||||||
BSC_REQUESTS_PER_MINUTE=2
|
BSC_REQUESTS_PER_MINUTE=8
|
||||||
|
|
||||||
CELO_BASE_URL=https://forno.celo.org
|
CELO_BASE_URL=https://forno.celo.org
|
||||||
CELO_REQUESTS_PER_MINUTE=2
|
CELO_REQUESTS_PER_MINUTE=2
|
||||||
|
|
||||||
ETHEREUM_BASE_URL=https://rpc.ankr.com/eth
|
ETHEREUM_BASE_URL=https://rpc.ankr.com/eth
|
||||||
ETHEREUM_REQUESTS_PER_MINUTE=2
|
ETHEREUM_REQUESTS_PER_MINUTE=8
|
||||||
|
|
||||||
FANTOM_BASE_URL=https://rpc.ankr.com/fantom
|
FANTOM_BASE_URL=https://rpc.ankr.com/fantom
|
||||||
FANTOM_REQUESTS_PER_MINUTE=2
|
FANTOM_REQUESTS_PER_MINUTE=2
|
||||||
|
@ -59,10 +59,10 @@ OPTIMISM_BASE_URL=https://rpc.ankr.com/optimism
|
||||||
OPTIMISM_REQUESTS_PER_MINUTE=2
|
OPTIMISM_REQUESTS_PER_MINUTE=2
|
||||||
|
|
||||||
POLYGON_BASE_URL=https://rpc.ankr.com/polygon
|
POLYGON_BASE_URL=https://rpc.ankr.com/polygon
|
||||||
POLYGON_REQUESTS_PER_MINUTE=2
|
POLYGON_REQUESTS_PER_MINUTE=8
|
||||||
|
|
||||||
SOLANA_BASE_URL=https://api.mainnet-beta.solana.com
|
SOLANA_BASE_URL=https://api.mainnet-beta.solana.com
|
||||||
SOLANA_REQUESTS_PER_MINUTE=2
|
SOLANA_REQUESTS_PER_MINUTE=12
|
||||||
|
|
||||||
SUI_BASE_URL=https://fullnode.mainnet.sui.io:443
|
SUI_BASE_URL=https://fullnode.mainnet.sui.io:443
|
||||||
SUI_REQUESTS_PER_MINUTE=2
|
SUI_REQUESTS_PER_MINUTE=2
|
||||||
|
|
|
@ -42,7 +42,6 @@ func fetchAlgorandTx(
|
||||||
txDetail := TxDetail{
|
txDetail := TxDetail{
|
||||||
NativeTxHash: response.Transaction.ID,
|
NativeTxHash: response.Transaction.ID,
|
||||||
From: response.Transaction.Sender,
|
From: response.Transaction.Sender,
|
||||||
Timestamp: time.Unix(int64(response.Transaction.RoundTime), 0),
|
|
||||||
}
|
}
|
||||||
return &txDetail, nil
|
return &txDetail, nil
|
||||||
}
|
}
|
||||||
|
|
|
@ -85,7 +85,6 @@ func fetchAptosTx(
|
||||||
TxDetail := TxDetail{
|
TxDetail := TxDetail{
|
||||||
NativeTxHash: tx.Hash,
|
NativeTxHash: tx.Hash,
|
||||||
From: tx.Sender,
|
From: tx.Sender,
|
||||||
Timestamp: time.UnixMicro(int64(tx.Timestamp)),
|
|
||||||
}
|
}
|
||||||
return &TxDetail, nil
|
return &TxDetail, nil
|
||||||
}
|
}
|
||||||
|
|
|
@ -65,16 +65,9 @@ func fetchCosmosTx(
|
||||||
return nil, fmt.Errorf("failed to find sender address in cosmos tx response")
|
return nil, fmt.Errorf("failed to find sender address in cosmos tx response")
|
||||||
}
|
}
|
||||||
|
|
||||||
// Parse the timestamp
|
|
||||||
timestamp, err := time.Parse("2006-01-02T15:04:05Z", response.TxResponse.Timestamp)
|
|
||||||
if err != nil {
|
|
||||||
return nil, fmt.Errorf("failed to parse tx timestamp from cosmos tx response: %w", err)
|
|
||||||
}
|
|
||||||
|
|
||||||
// Build the result object and return
|
// Build the result object and return
|
||||||
TxDetail := &TxDetail{
|
TxDetail := &TxDetail{
|
||||||
From: sender,
|
From: sender,
|
||||||
Timestamp: timestamp,
|
|
||||||
NativeTxHash: response.TxResponse.TxHash,
|
NativeTxHash: response.TxResponse.TxHash,
|
||||||
}
|
}
|
||||||
return TxDetail, nil
|
return TxDetail, nil
|
||||||
|
|
|
@ -45,29 +45,9 @@ func fetchEthTx(
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
// query block data
|
|
||||||
var blkReply ethGetBlockByHashResponse
|
|
||||||
{
|
|
||||||
blkParams := []interface{}{
|
|
||||||
txReply.BlockHash, // tx hash
|
|
||||||
false, // include transactions?
|
|
||||||
}
|
|
||||||
err = client.CallContext(ctx, rateLimiter, &blkReply, "eth_getBlockByHash", blkParams...)
|
|
||||||
if err != nil {
|
|
||||||
return nil, fmt.Errorf("failed to get block by hash: %w", err)
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
// parse transaction timestamp
|
|
||||||
timestamp, err := timestampFromHex(blkReply.Timestamp)
|
|
||||||
if err != nil {
|
|
||||||
return nil, fmt.Errorf("failed to parse block timestamp: %w", err)
|
|
||||||
}
|
|
||||||
|
|
||||||
// build results and return
|
// build results and return
|
||||||
txDetail := &TxDetail{
|
txDetail := &TxDetail{
|
||||||
From: strings.ToLower(txReply.From),
|
From: strings.ToLower(txReply.From),
|
||||||
Timestamp: timestamp,
|
|
||||||
NativeTxHash: fmt.Sprintf("0x%s", strings.ToLower(txHash)),
|
NativeTxHash: fmt.Sprintf("0x%s", strings.ToLower(txHash)),
|
||||||
}
|
}
|
||||||
return txDetail, nil
|
return txDetail, nil
|
||||||
|
|
|
@ -100,7 +100,6 @@ func fetchSolanaTx(
|
||||||
|
|
||||||
// populate the response object
|
// populate the response object
|
||||||
txDetail := TxDetail{
|
txDetail := TxDetail{
|
||||||
Timestamp: time.Unix(response.BlockTime, 0).UTC(),
|
|
||||||
NativeTxHash: sigs[0].Signature,
|
NativeTxHash: sigs[0].Signature,
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
|
@ -61,7 +61,6 @@ func fetchSuiTx(
|
||||||
txDetail := TxDetail{
|
txDetail := TxDetail{
|
||||||
NativeTxHash: reply.Digest,
|
NativeTxHash: reply.Digest,
|
||||||
From: reply.Transaction.Data.Sender,
|
From: reply.Transaction.Data.Sender,
|
||||||
Timestamp: time.UnixMilli(reply.TimestampMs),
|
|
||||||
}
|
}
|
||||||
return &txDetail, nil
|
return &txDetail, nil
|
||||||
}
|
}
|
||||||
|
|
|
@ -26,8 +26,6 @@ var (
|
||||||
type TxDetail struct {
|
type TxDetail struct {
|
||||||
// From is the address that signed the transaction, encoded in the chain's native format.
|
// From is the address that signed the transaction, encoded in the chain's native format.
|
||||||
From string
|
From string
|
||||||
// Timestamp indicates the time at which the transaction was confirmed.
|
|
||||||
Timestamp time.Time
|
|
||||||
// NativeTxHash contains the transaction hash, encoded in the chain's native format.
|
// NativeTxHash contains the transaction hash, encoded in the chain's native format.
|
||||||
NativeTxHash string
|
NativeTxHash string
|
||||||
}
|
}
|
||||||
|
|
|
@ -297,6 +297,7 @@ func consume(ctx context.Context, params *consumerParams) {
|
||||||
Emitter: v.EmitterAddr,
|
Emitter: v.EmitterAddr,
|
||||||
Sequence: v.Sequence,
|
Sequence: v.Sequence,
|
||||||
TxHash: *v.TxHash,
|
TxHash: *v.TxHash,
|
||||||
|
Overwrite: true, // Overwrite old contents
|
||||||
}
|
}
|
||||||
err := consumer.ProcessSourceTx(ctx, params.logger, params.rpcProviderSettings, params.repository, &p)
|
err := consumer.ProcessSourceTx(ctx, params.logger, params.rpcProviderSettings, params.repository, &p)
|
||||||
if err != nil {
|
if err != nil {
|
||||||
|
|
|
@ -2,18 +2,12 @@ package consumer
|
||||||
|
|
||||||
import (
|
import (
|
||||||
"context"
|
"context"
|
||||||
"time"
|
|
||||||
|
|
||||||
"github.com/wormhole-foundation/wormhole-explorer/txtracker/config"
|
"github.com/wormhole-foundation/wormhole-explorer/txtracker/config"
|
||||||
"github.com/wormhole-foundation/wormhole-explorer/txtracker/queue"
|
"github.com/wormhole-foundation/wormhole-explorer/txtracker/queue"
|
||||||
"go.uber.org/zap"
|
"go.uber.org/zap"
|
||||||
)
|
)
|
||||||
|
|
||||||
const (
|
|
||||||
maxAttempts = 5
|
|
||||||
retryDelay = 60 * time.Second
|
|
||||||
)
|
|
||||||
|
|
||||||
// Consumer consumer struct definition.
|
// Consumer consumer struct definition.
|
||||||
type Consumer struct {
|
type Consumer struct {
|
||||||
consumeFunc queue.VAAConsumeFunc
|
consumeFunc queue.VAAConsumeFunc
|
||||||
|
@ -56,6 +50,8 @@ func (c *Consumer) producerLoop(ctx context.Context) {
|
||||||
|
|
||||||
for msg := range ch {
|
for msg := range ch {
|
||||||
|
|
||||||
|
c.logger.Debug("Received message, pushing to worker pool", zap.String("vaaId", msg.Data().ID))
|
||||||
|
|
||||||
// Send the VAA to the worker pool.
|
// Send the VAA to the worker pool.
|
||||||
//
|
//
|
||||||
// The worker pool is responsible for calling `msg.Done()`
|
// The worker pool is responsible for calling `msg.Done()`
|
||||||
|
|
|
@ -12,6 +12,13 @@ import (
|
||||||
"go.uber.org/zap"
|
"go.uber.org/zap"
|
||||||
)
|
)
|
||||||
|
|
||||||
|
const (
|
||||||
|
maxAttempts = 1
|
||||||
|
retryDelay = 5 * time.Minute
|
||||||
|
)
|
||||||
|
|
||||||
|
var ErrAlreadyProcessed = errors.New("VAA was already processed")
|
||||||
|
|
||||||
// ProcessSourceTxParams is a struct that contains the parameters for the ProcessSourceTx method.
|
// ProcessSourceTxParams is a struct that contains the parameters for the ProcessSourceTx method.
|
||||||
type ProcessSourceTxParams struct {
|
type ProcessSourceTxParams struct {
|
||||||
ChainId sdk.ChainID
|
ChainId sdk.ChainID
|
||||||
|
@ -19,6 +26,13 @@ type ProcessSourceTxParams struct {
|
||||||
Emitter string
|
Emitter string
|
||||||
Sequence string
|
Sequence string
|
||||||
TxHash string
|
TxHash string
|
||||||
|
// Overwrite indicates whether to reprocess a VAA that has already been processed.
|
||||||
|
//
|
||||||
|
// In the context of backfilling, sometimes you want to overwrite old data (e.g.: because
|
||||||
|
// the schema changed).
|
||||||
|
// In the context of the service, you usually don't want to overwrite existing data
|
||||||
|
// to avoid processing the same VAA twice, which would result in performance degradation.
|
||||||
|
Overwrite bool
|
||||||
}
|
}
|
||||||
|
|
||||||
func ProcessSourceTx(
|
func ProcessSourceTx(
|
||||||
|
@ -37,6 +51,21 @@ func ProcessSourceTx(
|
||||||
var err error
|
var err error
|
||||||
for attempts := 1; attempts <= maxAttempts; attempts++ {
|
for attempts := 1; attempts <= maxAttempts; attempts++ {
|
||||||
|
|
||||||
|
if !params.Overwrite {
|
||||||
|
// If the message has already been processed, skip it.
|
||||||
|
//
|
||||||
|
// Sometimes the SQS visibility timeout expires and the message is put back into the queue,
|
||||||
|
// even if the RPC nodes have been hit and data has been written to MongoDB.
|
||||||
|
// In those cases, when we fetch the message for the second time,
|
||||||
|
// we don't want to hit the RPC nodes again for performance reasons.
|
||||||
|
processed, err := repository.AlreadyProcessed(ctx, params.VaaId)
|
||||||
|
if err != nil {
|
||||||
|
return err
|
||||||
|
} else if err == nil && processed {
|
||||||
|
return ErrAlreadyProcessed
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
txDetail, err = chains.FetchTx(ctx, rpcServiceProviderSettings, params.ChainId, params.TxHash)
|
txDetail, err = chains.FetchTx(ctx, rpcServiceProviderSettings, params.ChainId, params.TxHash)
|
||||||
|
|
||||||
switch {
|
switch {
|
||||||
|
|
|
@ -77,6 +77,24 @@ func (r *Repository) UpsertDocument(ctx context.Context, params *UpsertDocumentP
|
||||||
return nil
|
return nil
|
||||||
}
|
}
|
||||||
|
|
||||||
|
// AlreadyProcessed returns true if the given VAA ID has already been processed.
|
||||||
|
func (r *Repository) AlreadyProcessed(ctx context.Context, vaaId string) (bool, error) {
|
||||||
|
|
||||||
|
result := r.
|
||||||
|
globalTransactions.
|
||||||
|
FindOne(ctx, bson.D{{"_id", vaaId}})
|
||||||
|
|
||||||
|
var tx GlobalTransaction
|
||||||
|
err := result.Decode(&tx)
|
||||||
|
if err == mongo.ErrNoDocuments {
|
||||||
|
return false, nil
|
||||||
|
} else if err != nil {
|
||||||
|
return false, fmt.Errorf("failed to decode already processed VAA id: %w", err)
|
||||||
|
} else {
|
||||||
|
return true, nil
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
// CountDocumentsByTimeRange returns the number of documents that match the given time range.
|
// CountDocumentsByTimeRange returns the number of documents that match the given time range.
|
||||||
func (r *Repository) CountDocumentsByTimeRange(
|
func (r *Repository) CountDocumentsByTimeRange(
|
||||||
ctx context.Context,
|
ctx context.Context,
|
||||||
|
|
|
@ -102,19 +102,23 @@ func (w *WorkerPool) process(msg queue.ConsumerMessage) {
|
||||||
|
|
||||||
event := msg.Data()
|
event := msg.Data()
|
||||||
|
|
||||||
// Check if the message is expired
|
// Do not process messages from PythNet
|
||||||
if msg.IsExpired() {
|
if event.ChainID == sdk.ChainIDPythNet {
|
||||||
w.logger.Warn("Message with VAA expired",
|
if !msg.IsExpired() {
|
||||||
zap.String("vaaId", event.ID),
|
w.logger.Debug("Deleting PythNet message", zap.String("vaaId", event.ID))
|
||||||
zap.Bool("isExpired", msg.IsExpired()),
|
msg.Done()
|
||||||
)
|
} else {
|
||||||
msg.Failed()
|
w.logger.Debug("Skipping expired PythNet message", zap.String("vaaId", event.ID))
|
||||||
|
}
|
||||||
return
|
return
|
||||||
}
|
}
|
||||||
|
|
||||||
// Do not process messages from PythNet
|
// Skip non-processed, expired messages
|
||||||
if event.ChainID == sdk.ChainIDPythNet {
|
if msg.IsExpired() {
|
||||||
msg.Done()
|
w.logger.Warn("Message expired - skipping",
|
||||||
|
zap.String("vaaId", event.ID),
|
||||||
|
zap.Bool("isExpired", msg.IsExpired()),
|
||||||
|
)
|
||||||
return
|
return
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -125,6 +129,7 @@ func (w *WorkerPool) process(msg queue.ConsumerMessage) {
|
||||||
Emitter: event.EmitterAddress,
|
Emitter: event.EmitterAddress,
|
||||||
Sequence: event.Sequence,
|
Sequence: event.Sequence,
|
||||||
TxHash: event.TxHash,
|
TxHash: event.TxHash,
|
||||||
|
Overwrite: false, // avoid processing the same transaction twice
|
||||||
}
|
}
|
||||||
err := ProcessSourceTx(w.ctx, w.logger, w.rpcProviderSettings, w.repository, &p)
|
err := ProcessSourceTx(w.ctx, w.logger, w.rpcProviderSettings, w.repository, &p)
|
||||||
|
|
||||||
|
@ -133,6 +138,10 @@ func (w *WorkerPool) process(msg queue.ConsumerMessage) {
|
||||||
w.logger.Info("Skipping VAA - chain not supported",
|
w.logger.Info("Skipping VAA - chain not supported",
|
||||||
zap.String("vaaId", event.ID),
|
zap.String("vaaId", event.ID),
|
||||||
)
|
)
|
||||||
|
} else if err == ErrAlreadyProcessed {
|
||||||
|
w.logger.Warn("Message already processed - skipping",
|
||||||
|
zap.String("vaaId", event.ID),
|
||||||
|
)
|
||||||
} else if err != nil {
|
} else if err != nil {
|
||||||
w.logger.Error("Failed to process originTx",
|
w.logger.Error("Failed to process originTx",
|
||||||
zap.String("vaaId", event.ID),
|
zap.String("vaaId", event.ID),
|
||||||
|
@ -144,5 +153,10 @@ func (w *WorkerPool) process(msg queue.ConsumerMessage) {
|
||||||
)
|
)
|
||||||
}
|
}
|
||||||
|
|
||||||
|
// Mark the message as done
|
||||||
|
//
|
||||||
|
// If the message is expired, it will be put back into the queue.
|
||||||
|
if !msg.IsExpired() {
|
||||||
msg.Done()
|
msg.Done()
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
Loading…
Reference in New Issue