Skip to content

Commit d435e1e

Browse files
guide
1 parent 29a8ec2 commit d435e1e

File tree

3 files changed

+127
-1
lines changed

3 files changed

+127
-1
lines changed
Lines changed: 2 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -1,3 +1,4 @@
11
{
2-
"graph-client": "Graph Client"
2+
"graph-client": "Graph Client",
3+
"distributed-systems-guide": "How to Retrieve Consistent Data in a Distributed Environment"
34
}

website/src/pages/en/subgraphs/querying/_meta.js

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -6,6 +6,7 @@ export default {
66
'best-practices': '',
77
'from-an-application': '',
88
'distributed-systems': '',
9+
'distributed-systems-guide': '',
910
'graphql-api': '',
1011
'subgraph-id-vs-deployment-id': '',
1112
'graph-client': titles['graph-client'] ?? '',
Lines changed: 124 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,124 @@
1+
---
2+
title: How to Retrieve Consistent Data in a Distributed Environment
3+
---
4+
5+
Below are two distinct how-to scenarios that demonstrate how to maintain consistent data when querying The Graph in a distributed setting.
6+
7+
By following these steps, you can avoid data inconsistencies that arise from block reorganizations (re-orgs) or network fluctuations.
8+
9+
## How to Poll for Updated Data
10+
11+
When you need to fetch the newest information from The Graph without stepping back to an older block:
12+
13+
1. **Initialize a minimal block target:** Start by setting `minBlock` to 0 (or a known block number). This ensures your query will be served from the most recent block.
14+
2. **Set up a periodic polling cycle:** Choose a delay that matches the block production interval (e.g., 14 seconds). This ensures you wait until a new block is likely available.
15+
3. **Use the `block: { number_gte: $minBlock }` argument:** This ensures the fetched data is from a block at or above the specified block number, preventing time from moving backward.
16+
4. **Handle logic inside the loop:** Update `minBlock` to the most recent block returned in each iteration.
17+
5. **Process the fetched data:** Implement the necessary actions (e.g., updating internal state) with the newly polled data.
18+
19+
```javascript
20+
/// Example: Polling for updated data
21+
async function updateProtocolPaused() {
22+
let minBlock = 0;
23+
24+
for (;;) {
25+
// Wait for the next block.
26+
const nextBlock = new Promise((f) => {
27+
setTimeout(f, 14000);
28+
});
29+
30+
const query = `
31+
query GetProtocol($minBlock: Int!) {
32+
protocol(block: { number_gte: $minBlock }, id: "0") {
33+
paused
34+
}
35+
_meta {
36+
block {
37+
number
38+
}
39+
}
40+
}
41+
`;
42+
43+
const variables = { minBlock };
44+
const response = await graphql(query, variables);
45+
minBlock = response._meta.block.number;
46+
47+
// TODO: Replace this placeholder with handling of 'response.protocol.paused'.
48+
console.log(response.protocol.paused);
49+
50+
// Wait to poll again.
51+
await nextBlock;
52+
}
53+
}
54+
```
55+
56+
## How to Fetch a Set of Related Items from a Single Block
57+
58+
If you must retrieve multiple related items or a large set of data from the same point in time:
59+
60+
1. **Fetch the initial page:** Use a query that includes `_meta { block { hash } }` to capture the block hash. This ensures subsequent queries stay pinned to that same block.
61+
2. **Store the block hash:** Keep the hash from the first response. This becomes your reference point for the rest of the items.
62+
3. **Paginate the results:** Make additional requests using the same block hash and a pagination strategy (e.g., `id_gt` or other filtering) until you have fetched all relevant items.
63+
4. **Handle re-orgs:** If the block hash becomes invalid due to a re-org, retry from the first request to obtain a non-uncle block.
64+
65+
```javascript
66+
/// Example: Fetching a large set of related items
67+
async function getDomainNames() {
68+
let pages = 5;
69+
const perPage = 1000;
70+
71+
// First request captures the block hash.
72+
const listDomainsQuery = `
73+
query ListDomains($perPage: Int!) {
74+
domains(first: $perPage) {
75+
name
76+
id
77+
}
78+
_meta {
79+
block {
80+
hash
81+
}
82+
}
83+
}
84+
`;
85+
86+
let data = await graphql(listDomainsQuery, { perPage });
87+
let result = data.domains.map((d) => d.name);
88+
let blockHash = data._meta.block.hash;
89+
90+
// Paginate until fewer than 'perPage' results are returned or you reach the page limit.
91+
while (data.domains.length === perPage && --pages) {
92+
let lastID = data.domains[data.domains.length - 1].id;
93+
let query = `
94+
query ListDomains($perPage: Int!, $lastID: ID!, $blockHash: Bytes!) {
95+
domains(
96+
first: $perPage
97+
where: { id_gt: $lastID }
98+
block: { hash: $blockHash }
99+
) {
100+
name
101+
id
102+
}
103+
}
104+
`;
105+
106+
data = await graphql(query, { perPage, lastID, blockHash });
107+
108+
for (const domain of data.domains) {
109+
result.push(domain.name);
110+
}
111+
}
112+
113+
// TODO: Do something with the full result.
114+
return result;
115+
}
116+
```
117+
118+
## Recap and Next Steps
119+
120+
By using the `number_gte` parameter in a polling loop, you ensure time moves forward when fetching updates. By pinning queries to a specific `block.hash`, you can retrieve multiple sets of related information consistently from the same block.
121+
122+
• If you encounter re-orgs, plan to retry from the beginning or adjust your logic accordingly. • Explore other filtering and block arguments (see \[placeholder for reference location\]) to handle additional use-cases.
123+
124+
\[Placeholder for additional references or external resources if available\]

0 commit comments

Comments
 (0)