Skip to content

Commit

Permalink
PKG -- [FCL] Ignore 404 errors when polling transaction status
Browse files Browse the repository at this point in the history
  • Loading branch information
jribbink committed Oct 25, 2023
1 parent e0d0d14 commit f2fd09c
Show file tree
Hide file tree
Showing 5 changed files with 45 additions and 4 deletions.
5 changes: 5 additions & 0 deletions .changeset/olive-chairs-jump.md
Original file line number Diff line number Diff line change
@@ -0,0 +1,5 @@
---
"@onflow/transport-http": minor
---

Export HTTPRequestError
5 changes: 5 additions & 0 deletions .changeset/orange-turkeys-wonder.md
Original file line number Diff line number Diff line change
@@ -0,0 +1,5 @@
---
"@onflow/fcl": patch
---

Ignore Not Found errors when polling transaction status (workaround for access node load balancers)
36 changes: 33 additions & 3 deletions packages/fcl/src/transaction/index.js
Original file line number Diff line number Diff line change
Expand Up @@ -10,6 +10,10 @@ import {
UNSUBSCRIBE,
} from "@onflow/util-actor"
import {send as fclSend, decode, getTransactionStatus} from "@onflow/sdk"
import {HTTPRequestError} from "@onflow/transport-http"
import {grpc} from "@improbable-eng/grpc-web"

const TXID_REGEXP = /^[0-9a-fA-F]{64}$/

/**
* @typedef {import("@onflow/typedefs").Transaction} Transaction
Expand All @@ -20,7 +24,9 @@ import {send as fclSend, decode, getTransactionStatus} from "@onflow/sdk"
*/

const RATE = 2500
const NOT_FOUND_TIMEOUT = 10000
const POLL = "POLL"
const TIMEOUT = "TIMEOUT"

const fetchTxStatus = async transactionId => {
return fclSend([getTransactionStatus(transactionId)]).then(decode)
Expand All @@ -39,6 +45,7 @@ const isDiff = (cur, next) => {

const HANDLERS = {
[INIT]: async ctx => {
setTimeout(() => ctx.sendSelf(TIMEOUT), NOT_FOUND_TIMEOUT)
ctx.sendSelf(POLL)
},
[SUBSCRIBE]: (ctx, letter) => {
Expand All @@ -51,16 +58,35 @@ const HANDLERS = {
[SNAPSHOT]: async (ctx, letter) => {
letter.reply(ctx.all())
},
[TIMEOUT]: async ctx => {
// If status is still unknown, send a timeout error
if (Object.keys(ctx.all()).length === 0) {
ctx.fatalError(new Error("Transaction not found within timeout interval"))
}
},
[POLL]: async ctx => {
// Helper to queue another poll
const poll = () => setTimeout(() => ctx.sendSelf(POLL), RATE)

let tx
const prevTx = ctx.all()
try {
tx = await fetchTxStatus(ctx.self())
} catch (e) {
const isHttpNotFound =
e instanceof HTTPRequestError && e.statusCode === 404
const isGrpcNotFound = e.code === grpc.Code.NotFound

// If TX is not found, suppress error and poll again
if (isHttpNotFound || isGrpcNotFound) {
return poll()
}

return ctx.fatalError(e)
}

if (!isSealed(tx)) setTimeout(() => ctx.sendSelf(POLL), RATE)
if (isDiff(ctx.all(), tx)) ctx.broadcast(UPDATED, tx)
if (!isSealed(tx)) poll()
if (isDiff(prevTx, tx)) ctx.broadcast(UPDATED, tx)
ctx.merge(tx)
},
}
Expand All @@ -84,7 +110,7 @@ const spawnTransaction = transactionId => {

/**
* Provides methods for interacting with a transaction
*
*
* @param {string} transactionId - The transaction ID
* @returns {{
* snapshot: function(): Promise<TransactionStatus>,
Expand All @@ -95,6 +121,10 @@ const spawnTransaction = transactionId => {
* }}
*/
export function transaction(transactionId) {
// Validate transactionId as 64 byte hash
if (!TXID_REGEXP.test(scoped(transactionId)))
throw new Error("Invalid transactionId")

function snapshot() {
return snapshoter(transactionId, spawnTransaction)
}
Expand Down
2 changes: 1 addition & 1 deletion packages/transport-http/src/http-request.js
Original file line number Diff line number Diff line change
Expand Up @@ -4,7 +4,7 @@ import fetchTransport from "cross-fetch"
const AbortController =
globalThis.AbortController || require("abort-controller")

class HTTPRequestError extends Error {
export class HTTPRequestError extends Error {
constructor({
error,
hostname,
Expand Down
1 change: 1 addition & 0 deletions packages/transport-http/src/sdk-send-http.js
Original file line number Diff line number Diff line change
Expand Up @@ -10,3 +10,4 @@ export {sendPing} from "./send-ping.js"
export {sendTransaction} from "./send-transaction.js"
export {sendGetNetworkParameters} from "./send-get-network-parameters.js"
export {send} from "./send-http.js"
export {HTTPRequestError} from "./http-request.js"

0 comments on commit f2fd09c

Please sign in to comment.