Skip to content

Commit

Permalink
feat: add ping option to fallback transport (#2642)
Browse files Browse the repository at this point in the history
* adding rankMethod parameter to fallback transport

* chore: tweaks

* chore: tweaks

* chore: tweaks

* chore: tweaks

* chore: changeset

---------

Co-authored-by: jxom <[email protected]>
  • Loading branch information
0x33dm and jxom authored Nov 29, 2024
1 parent 0ea09cc commit d1d092c
Show file tree
Hide file tree
Showing 4 changed files with 76 additions and 1 deletion.
5 changes: 5 additions & 0 deletions .changeset/new-papayas-draw.md
Original file line number Diff line number Diff line change
@@ -0,0 +1,5 @@
---
"viem": patch
---

Added `ping` option to `fallback` Transport.
21 changes: 21 additions & 0 deletions site/pages/docs/clients/transports/fallback.md
Original file line number Diff line number Diff line change
Expand Up @@ -114,6 +114,27 @@ const transport = fallback([alchemy, infura], {
})
```

### rank.ping (optional)

- **Type:** `({ transport }: { transport: Transport }) => Promise<unknown>`
- **Default:** `({ transport }) => transport.request({ method: 'net_listening' })`

Function to call to ping the Transport. Defaults to calling the `net_listening` method to check if the Transport is online.

```ts twoslash
// @noErrors
import { createPublicClient, fallback, http } from 'viem'
import { mainnet } from 'viem/chains'
const alchemy = http('')
const infura = http('')
// ---cut---
const transport = fallback([alchemy, infura], {
rank: { // [!code focus:3]
ping: ({ transport }) => transport.request({ method: 'eth_blockNumber' })
},
})
```

### rank.sampleCount (optional)

- **Type:** `number`
Expand Down
38 changes: 38 additions & 0 deletions src/clients/transports/fallback.test.ts
Original file line number Diff line number Diff line change
Expand Up @@ -828,4 +828,42 @@ describe('rankTransports', () => {
]
`)
})

test('behavior: custom ping', async () => {
const results: { method: string }[] = []

const server = await createHttpServer((req, res) => {
req.setEncoding('utf8')
req.on('data', (body) => {
results.push(JSON.parse(body))
res.writeHead(200, { 'Content-Type': 'application/json' })
res.end(JSON.stringify({ result: '0x1' }))
})
})

const transport1 = http(server.url, { key: '1' })

let count = 0
rankTransports({
chain: localhost,
interval: 10,
transports: [transport1],
onTransports() {},
ping({ transport }) {
count++
return transport.request({
method: count % 2 === 0 ? 'eth_blockNumber' : 'eth_getBlockByNumber',
})
},
})

await wait(20)

expect(results.map((r) => r.method)).toMatchInlineSnapshot(`
[
"eth_getBlockByNumber",
"eth_blockNumber",
]
`)
})
})
13 changes: 12 additions & 1 deletion src/clients/transports/fallback.ts
Original file line number Diff line number Diff line change
Expand Up @@ -38,6 +38,12 @@ type RankOptions = {
* @default client.pollingInterval
*/
interval?: number | undefined
/**
* Ping method to determine latency.
*/
ping?: (parameters: { transport: ReturnType<Transport> }) =>
| Promise<unknown>
| undefined
/**
* The number of previous samples to perform ranking on.
* @default 10
Expand Down Expand Up @@ -173,6 +179,7 @@ export function fallback<const transports extends readonly Transport[]>(
chain,
interval: rankOptions.interval ?? pollingInterval,
onTransports: (transports_) => (transports = transports_ as transports),
ping: rankOptions.ping,
sampleCount: rankOptions.sampleCount,
timeout: rankOptions.timeout,
transports,
Expand Down Expand Up @@ -200,6 +207,7 @@ export function rankTransports({
chain,
interval = 4_000,
onTransports,
ping,
sampleCount = 10,
timeout = 1_000,
transports,
Expand All @@ -208,6 +216,7 @@ export function rankTransports({
chain?: Chain | undefined
interval: RankOptions['interval']
onTransports: (transports: readonly Transport[]) => void
ping?: RankOptions['ping'] | undefined
sampleCount?: RankOptions['sampleCount'] | undefined
timeout?: RankOptions['timeout'] | undefined
transports: readonly Transport[]
Expand All @@ -230,7 +239,9 @@ export function rankTransports({
let end: number
let success: number
try {
await transport_.request({ method: 'net_listening' })
await (ping
? ping({ transport: transport_ })
: transport_.request({ method: 'net_listening' }))
success = 1
} catch {
success = 0
Expand Down

0 comments on commit d1d092c

Please sign in to comment.