From 29a8ec2508e287b5435515c94a2b37d1dbe5d836 Mon Sep 17 00:00:00 2001 From: Michael Macaulay Date: Thu, 29 May 2025 12:56:58 -0400 Subject: [PATCH 1/7] Explanation --- .../querying/distributed-systems.mdx | 93 ++++++++++--------- 1 file changed, 49 insertions(+), 44 deletions(-) diff --git a/website/src/pages/en/subgraphs/querying/distributed-systems.mdx b/website/src/pages/en/subgraphs/querying/distributed-systems.mdx index 85337206bfd3..12460cc51ba8 100644 --- a/website/src/pages/en/subgraphs/querying/distributed-systems.mdx +++ b/website/src/pages/en/subgraphs/querying/distributed-systems.mdx @@ -2,56 +2,60 @@ title: Distributed Systems --- -The Graph is a protocol implemented as a distributed system. +Distributed systems offer vast capabilities, but they also come with inherent complexities. In **The Graph**, these complexities are amplified at a global scale. -Connections fail. Requests arrive out of order. Different computers with out-of-sync clocks and states process related requests. Servers restart. Re-orgs happen between requests. These problems are inherent to all distributed systems but are exacerbated in systems operating at a global scale. +This document provides an explanation of why requests can appear inconsistent, how block reorganization (re-org) events affect data delivery, and why certain solutions exist to maintain consistency. -Consider this example of what may occur if a client polls an Indexer for the latest data during a re-org. +### Why Distributed Systems Can Appear Inconsistent -1. Indexer ingests block 8 -2. Request served to the client for block 8 -3. Indexer ingests block 9 -4. Indexer ingests block 10A -5. Request served to the client for block 10A -6. Indexer detects reorg to 10B and rolls back 10A -7. Request served to the client for block 9 -8. Indexer ingests block 10B -9. Indexer ingests block 11 +Whenever different computers are working together across the globe, certain problems become unavoidable. Connections fail, computers get restarted, and clocks fall out of sync. In the context of **The Graph**, multiple Indexers ingest blocks at slightly different times, and clients can make requests to any of these Indexers. The result is that requests may arrive out of order or be answered based on different block states. + +A perfect example of this is the so-called "block wobble" phenomenon, where a client sees block data appear to jump forward and backward in unexpected ways. This phenomenon becomes especially noticeable during a block re-org — a situation where a previously ingested block is replaced by a different one under consensus. + +#### Example of Block Reorganization + +To understand the impact, consider a scenario where a client continuously fetches the latest block from an Indexer: + +1. Indexer ingests block 8 +2. Request served to the client for block 8 +3. Indexer ingests block 9 +4. Indexer ingests block 10A +5. Request served to the client for block 10A +6. Indexer detects re-org to 10B and rolls back 10A +7. Request served to the client for block 9 +8. Indexer ingests block 10B +9. Indexer ingests block 11 10. Request served to the client for block 11 -From the point of view of the Indexer, things are progressing forward logically. Time is moving forward, though we did have to roll back an uncle block and play the block under consensus forward on top of it. Along the way, the Indexer serves requests using the latest state it knows about at that time. +From the **Indexer's viewpoint**, it sees a forward-moving progression with a brief need to roll back an invalid block. But from the **client's viewpoint**, responses seem to arrive in a puzzling order: block 8, block 10, then suddenly block 9, and finally block 11. -From the point of view of the client, however, things appear chaotic. The client observes that the responses were for blocks 8, 10, 9, and 11 in that order. We call this the "block wobble" problem. When a client experiences block wobble, data may appear to contradict itself over time. The situation worsens when we consider that Indexers do not all ingest the latest blocks simultaneously, and your requests may be routed to multiple Indexers. +This disruption can cause data to appear contradictory. The challenge is magnified when clients are routed to multiple Indexers, each of which may be at different block heights. -It is the responsibility of the client and server to work together to provide consistent data to the user. Different approaches must be used depending on the desired consistency as there is no one right program for every problem. +### Why Consistency Matters -Reasoning through the implications of distributed systems is hard, but the fix may not be! We've established APIs and patterns to help you navigate some common use-cases. The following examples illustrate those patterns but still elide details required by production code (like error handling and cancellation) to not obfuscate the main ideas. +In a distributed protocol like **The Graph**, it is the responsibility of both client and server to coordinate on a consistency strategy. Systems often require different approaches based on their tolerance for receiving out-of-date data versus their need for up-to-the-moment accuracy. -## Polling for updated data +Reasoning through these distributed-system implications is difficult, but solutions exist to reduce confusion. For instance, certain patterns and APIs ensure either forward-only progress or consistent snapshot views of data. Below, two notable methods to maintain a clearer sense of order are explored. -The Graph provides the `block: { number_gte: $minBlock }` API, which ensures that the response is for a single block equal or higher to `$minBlock`. If the request is made to a `graph-node` instance and the min block is not yet synced, `graph-node` will return an error. If `graph-node` has synced min block, it will run the response for the latest block. If the request is made to an Edge & Node Gateway, the Gateway will filter out any Indexers that have not yet synced min block and make the request for the latest block the Indexer has synced. +### Ensuring Forward-Only Progress with Block Number Constraints -We can use `number_gte` to ensure that time never travels backward when polling for data in a loop. Here is an example: +Sometimes, your system only needs to avoid "going backward" in time. **The Graph** provides the `block: { number_gte: $minBlock }` argument to help support this by guaranteeing that returned data will always be from a block number equal to or greater than a specified minimum: ```javascript -/// Updates the protocol.paused variable to the latest -/// known value in a loop by fetching it using The Graph. +/// Updates the protocol.paused variable by always querying +/// for a block at or beyond the last known block. async function updateProtocolPaused() { - // It's ok to start with minBlock at 0. The query will be served - // using the latest block available. Setting minBlock to 0 is the - // same as leaving out that argument. let minBlock = 0 for (;;) { - // Schedule a promise that will be ready once - // the next Ethereum block will likely be available. + // Wait until the next block is likely available. const nextBlock = new Promise((f) => { setTimeout(f, 14000) }) const query = ` query GetProtocol($minBlock: Int!) { - protocol(block: { number_gte: $minBlock } id: "0") { + protocol(block: { number_gte: $minBlock }, id: "0") { paused } _meta { @@ -65,30 +69,27 @@ async function updateProtocolPaused() { const response = await graphql(query, variables) minBlock = response._meta.block.number - // TODO: Do something with the response data here instead of logging it. + // This ensures time never travels backward. console.log(response.protocol.paused) - // Sleep to wait for the next block + // Wait before fetching the next block. await nextBlock } } ``` -## Fetching a set of related items +In an environment with multiple Indexers, the Gateway can filter out Indexers not yet at `minBlock`, ensuring you consistently move forward in time. -Another use-case is retrieving a large set or, more generally, retrieving related items across multiple requests. Unlike the polling case (where the desired consistency was to move forward in time), the desired consistency is for a single point in time. +### Achieving a Consistent View with Block Hash Constraints -Here we will use the `block: { hash: $blockHash }` argument to pin all of our results to the same block. +In other scenarios, you need to retrieve multiple related data points or perform pagination without risking differences in blocks. This is where pinning a query to a single block hash becomes critical: ```javascript -/// Gets a list of domain names from a single block using pagination +/// Gets a list of domain names from a single block using pagination. async function getDomainNames() { - // Set a cap on the maximum number of items to pull. let pages = 5 const perPage = 1000 - // The first query will get the first page of results and also get the block - // hash so that the remainder of the queries are consistent with the first. const listDomainsQuery = ` query ListDomains($perPage: Int!) { domains(first: $perPage) { @@ -106,15 +107,15 @@ async function getDomainNames() { let result = data.domains.map((d) => d.name) let blockHash = data._meta.block.hash - let query - // Continue fetching additional pages until either we run into the limit of - // 5 pages total (specified above) or we know we have reached the last page - // because the page has fewer entities than a full page. while (data.domains.length == perPage && --pages) { let lastID = data.domains[data.domains.length - 1].id - query = ` + let query = ` query ListDomains($perPage: Int!, $lastID: ID!, $blockHash: Bytes!) { - domains(first: $perPage, where: { id_gt: $lastID }, block: { hash: $blockHash }) { + domains( + first: $perPage, + where: { id_gt: $lastID }, + block: { hash: $blockHash } + ) { name id } @@ -122,13 +123,17 @@ async function getDomainNames() { data = await graphql(query, { perPage, lastID, blockHash }) - // Accumulate domain names into the result for (domain of data.domains) { result.push(domain.name) } } + return result } ``` -Note that in case of a re-org, the client will need to retry from the first request to update the block hash to a non-uncle block. +By pinning queries to a single block hash, all responses relate to the same point in time, eliminating any variation caused by a re-org that might occur if different blocks were referenced. However, if a re-org does affect that chosen block, the client must repeat the process with a new canonical block hash. + +### Final Thoughts on Distributed Consistency + +Distributed systems can seem unpredictable, but understanding the root causes of events like out-of-order requests and block reorganizations helps clarify why the data may appear contradictory. By using the patterns described above, both crossing block boundaries forward in time and maintaining a single consistent block snapshot become possible strategies in managing this inherent complexity. From d435e1eaad2cb7b3de850b103259c9f39e63175b Mon Sep 17 00:00:00 2001 From: Michael Macaulay Date: Thu, 29 May 2025 13:07:00 -0400 Subject: [PATCH 2/7] guide --- .../en/subgraphs/querying/_meta-titles.json | 3 +- .../src/pages/en/subgraphs/querying/_meta.js | 1 + .../querying/distributed-systems-guide.mdx | 124 ++++++++++++++++++ 3 files changed, 127 insertions(+), 1 deletion(-) create mode 100644 website/src/pages/en/subgraphs/querying/distributed-systems-guide.mdx diff --git a/website/src/pages/en/subgraphs/querying/_meta-titles.json b/website/src/pages/en/subgraphs/querying/_meta-titles.json index a30daaefc9d0..4110aedf9d84 100644 --- a/website/src/pages/en/subgraphs/querying/_meta-titles.json +++ b/website/src/pages/en/subgraphs/querying/_meta-titles.json @@ -1,3 +1,4 @@ { - "graph-client": "Graph Client" + "graph-client": "Graph Client", + "distributed-systems-guide": "How to Retrieve Consistent Data in a Distributed Environment" } diff --git a/website/src/pages/en/subgraphs/querying/_meta.js b/website/src/pages/en/subgraphs/querying/_meta.js index aa7d6b63f4eb..0389427ddaee 100644 --- a/website/src/pages/en/subgraphs/querying/_meta.js +++ b/website/src/pages/en/subgraphs/querying/_meta.js @@ -6,6 +6,7 @@ export default { 'best-practices': '', 'from-an-application': '', 'distributed-systems': '', + 'distributed-systems-guide': '', 'graphql-api': '', 'subgraph-id-vs-deployment-id': '', 'graph-client': titles['graph-client'] ?? '', diff --git a/website/src/pages/en/subgraphs/querying/distributed-systems-guide.mdx b/website/src/pages/en/subgraphs/querying/distributed-systems-guide.mdx new file mode 100644 index 000000000000..7731650b5ea8 --- /dev/null +++ b/website/src/pages/en/subgraphs/querying/distributed-systems-guide.mdx @@ -0,0 +1,124 @@ +--- +title: How to Retrieve Consistent Data in a Distributed Environment +--- + +Below are two distinct how-to scenarios that demonstrate how to maintain consistent data when querying The Graph in a distributed setting. + +By following these steps, you can avoid data inconsistencies that arise from block reorganizations (re-orgs) or network fluctuations. + +## How to Poll for Updated Data + +When you need to fetch the newest information from The Graph without stepping back to an older block: + +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. +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. +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. +4. **Handle logic inside the loop:** Update `minBlock` to the most recent block returned in each iteration. +5. **Process the fetched data:** Implement the necessary actions (e.g., updating internal state) with the newly polled data. + +```javascript +/// Example: Polling for updated data +async function updateProtocolPaused() { + let minBlock = 0; + + for (;;) { + // Wait for the next block. + const nextBlock = new Promise((f) => { + setTimeout(f, 14000); + }); + + const query = ` + query GetProtocol($minBlock: Int!) { + protocol(block: { number_gte: $minBlock }, id: "0") { + paused + } + _meta { + block { + number + } + } + } + `; + + const variables = { minBlock }; + const response = await graphql(query, variables); + minBlock = response._meta.block.number; + + // TODO: Replace this placeholder with handling of 'response.protocol.paused'. + console.log(response.protocol.paused); + + // Wait to poll again. + await nextBlock; + } +} +``` + +## How to Fetch a Set of Related Items from a Single Block + +If you must retrieve multiple related items or a large set of data from the same point in time: + +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. +2. **Store the block hash:** Keep the hash from the first response. This becomes your reference point for the rest of the items. +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. +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. + +```javascript +/// Example: Fetching a large set of related items +async function getDomainNames() { + let pages = 5; + const perPage = 1000; + + // First request captures the block hash. + const listDomainsQuery = ` + query ListDomains($perPage: Int!) { + domains(first: $perPage) { + name + id + } + _meta { + block { + hash + } + } + } + `; + + let data = await graphql(listDomainsQuery, { perPage }); + let result = data.domains.map((d) => d.name); + let blockHash = data._meta.block.hash; + + // Paginate until fewer than 'perPage' results are returned or you reach the page limit. + while (data.domains.length === perPage && --pages) { + let lastID = data.domains[data.domains.length - 1].id; + let query = ` + query ListDomains($perPage: Int!, $lastID: ID!, $blockHash: Bytes!) { + domains( + first: $perPage + where: { id_gt: $lastID } + block: { hash: $blockHash } + ) { + name + id + } + } + `; + + data = await graphql(query, { perPage, lastID, blockHash }); + + for (const domain of data.domains) { + result.push(domain.name); + } + } + + // TODO: Do something with the full result. + return result; +} +``` + +## Recap and Next Steps + +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. + +• 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. + +\[Placeholder for additional references or external resources if available\] From 4771d95af2c635581c4e26800ccb8f557c23b32f Mon Sep 17 00:00:00 2001 From: Michael Macaulay Date: Thu, 29 May 2025 13:08:39 -0400 Subject: [PATCH 3/7] Fixes --- .../querying/distributed-systems-guide.mdx | 56 +++++++++---------- .../querying/distributed-systems.mdx | 20 +++---- 2 files changed, 38 insertions(+), 38 deletions(-) diff --git a/website/src/pages/en/subgraphs/querying/distributed-systems-guide.mdx b/website/src/pages/en/subgraphs/querying/distributed-systems-guide.mdx index 7731650b5ea8..ee675046c007 100644 --- a/website/src/pages/en/subgraphs/querying/distributed-systems-guide.mdx +++ b/website/src/pages/en/subgraphs/querying/distributed-systems-guide.mdx @@ -10,22 +10,22 @@ By following these steps, you can avoid data inconsistencies that arise from blo When you need to fetch the newest information from The Graph without stepping back to an older block: -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. -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. -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. -4. **Handle logic inside the loop:** Update `minBlock` to the most recent block returned in each iteration. +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. +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. +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. +4. **Handle logic inside the loop:** Update `minBlock` to the most recent block returned in each iteration. 5. **Process the fetched data:** Implement the necessary actions (e.g., updating internal state) with the newly polled data. ```javascript /// Example: Polling for updated data async function updateProtocolPaused() { - let minBlock = 0; + let minBlock = 0 for (;;) { // Wait for the next block. const nextBlock = new Promise((f) => { - setTimeout(f, 14000); - }); + setTimeout(f, 14000) + }) const query = ` query GetProtocol($minBlock: Int!) { @@ -38,17 +38,17 @@ async function updateProtocolPaused() { } } } - `; + ` - const variables = { minBlock }; - const response = await graphql(query, variables); - minBlock = response._meta.block.number; + const variables = { minBlock } + const response = await graphql(query, variables) + minBlock = response._meta.block.number // TODO: Replace this placeholder with handling of 'response.protocol.paused'. - console.log(response.protocol.paused); + console.log(response.protocol.paused) // Wait to poll again. - await nextBlock; + await nextBlock } } ``` @@ -57,16 +57,16 @@ async function updateProtocolPaused() { If you must retrieve multiple related items or a large set of data from the same point in time: -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. -2. **Store the block hash:** Keep the hash from the first response. This becomes your reference point for the rest of the items. -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. +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. +2. **Store the block hash:** Keep the hash from the first response. This becomes your reference point for the rest of the items. +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. 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. ```javascript /// Example: Fetching a large set of related items async function getDomainNames() { - let pages = 5; - const perPage = 1000; + let pages = 5 + const perPage = 1000 // First request captures the block hash. const listDomainsQuery = ` @@ -81,15 +81,15 @@ async function getDomainNames() { } } } - `; + ` - let data = await graphql(listDomainsQuery, { perPage }); - let result = data.domains.map((d) => d.name); - let blockHash = data._meta.block.hash; + let data = await graphql(listDomainsQuery, { perPage }) + let result = data.domains.map((d) => d.name) + let blockHash = data._meta.block.hash // Paginate until fewer than 'perPage' results are returned or you reach the page limit. while (data.domains.length === perPage && --pages) { - let lastID = data.domains[data.domains.length - 1].id; + let lastID = data.domains[data.domains.length - 1].id let query = ` query ListDomains($perPage: Int!, $lastID: ID!, $blockHash: Bytes!) { domains( @@ -101,17 +101,17 @@ async function getDomainNames() { id } } - `; + ` - data = await graphql(query, { perPage, lastID, blockHash }); + data = await graphql(query, { perPage, lastID, blockHash }) for (const domain of data.domains) { - result.push(domain.name); + result.push(domain.name) } } // TODO: Do something with the full result. - return result; + return result } ``` @@ -121,4 +121,4 @@ By using the `number_gte` parameter in a polling loop, you ensure time moves for • 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. -\[Placeholder for additional references or external resources if available\] +\[Placeholder for additional references or external resources if available\] diff --git a/website/src/pages/en/subgraphs/querying/distributed-systems.mdx b/website/src/pages/en/subgraphs/querying/distributed-systems.mdx index 12460cc51ba8..811c7aaaf9b4 100644 --- a/website/src/pages/en/subgraphs/querying/distributed-systems.mdx +++ b/website/src/pages/en/subgraphs/querying/distributed-systems.mdx @@ -16,15 +16,15 @@ A perfect example of this is the so-called "block wobble" phenomenon, where a cl To understand the impact, consider a scenario where a client continuously fetches the latest block from an Indexer: -1. Indexer ingests block 8 -2. Request served to the client for block 8 -3. Indexer ingests block 9 -4. Indexer ingests block 10A -5. Request served to the client for block 10A -6. Indexer detects re-org to 10B and rolls back 10A -7. Request served to the client for block 9 -8. Indexer ingests block 10B -9. Indexer ingests block 11 +1. Indexer ingests block 8 +2. Request served to the client for block 8 +3. Indexer ingests block 9 +4. Indexer ingests block 10A +5. Request served to the client for block 10A +6. Indexer detects re-org to 10B and rolls back 10A +7. Request served to the client for block 9 +8. Indexer ingests block 10B +9. Indexer ingests block 11 10. Request served to the client for block 11 From the **Indexer's viewpoint**, it sees a forward-moving progression with a brief need to roll back an invalid block. But from the **client's viewpoint**, responses seem to arrive in a puzzling order: block 8, block 10, then suddenly block 9, and finally block 11. @@ -136,4 +136,4 @@ By pinning queries to a single block hash, all responses relate to the same poin ### Final Thoughts on Distributed Consistency -Distributed systems can seem unpredictable, but understanding the root causes of events like out-of-order requests and block reorganizations helps clarify why the data may appear contradictory. By using the patterns described above, both crossing block boundaries forward in time and maintaining a single consistent block snapshot become possible strategies in managing this inherent complexity. +Distributed systems can seem unpredictable, but understanding the root causes of events like out-of-order requests and block reorganizations helps clarify why the data may appear contradictory. By using the patterns described above, both crossing block boundaries forward in time and maintaining a single consistent block snapshot become possible strategies in managing this inherent complexity. From c7e54ed179dd5a6dcf57b75bd650f2d6a15a0927 Mon Sep 17 00:00:00 2001 From: Michael Macaulay Date: Thu, 29 May 2025 13:13:51 -0400 Subject: [PATCH 4/7] Fix heading --- website/src/pages/en/subgraphs/querying/distributed-systems.mdx | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/website/src/pages/en/subgraphs/querying/distributed-systems.mdx b/website/src/pages/en/subgraphs/querying/distributed-systems.mdx index 811c7aaaf9b4..9460a8a6f5e0 100644 --- a/website/src/pages/en/subgraphs/querying/distributed-systems.mdx +++ b/website/src/pages/en/subgraphs/querying/distributed-systems.mdx @@ -6,7 +6,7 @@ Distributed systems offer vast capabilities, but they also come with inherent co This document provides an explanation of why requests can appear inconsistent, how block reorganization (re-org) events affect data delivery, and why certain solutions exist to maintain consistency. -### Why Distributed Systems Can Appear Inconsistent +## Why Distributed Systems Can Appear Inconsistent Whenever different computers are working together across the globe, certain problems become unavoidable. Connections fail, computers get restarted, and clocks fall out of sync. In the context of **The Graph**, multiple Indexers ingest blocks at slightly different times, and clients can make requests to any of these Indexers. The result is that requests may arrive out of order or be answered based on different block states. From c990bf0d837c99be3369c6f4c2638e379cec72da Mon Sep 17 00:00:00 2001 From: Michael Macaulay Date: Thu, 29 May 2025 13:17:40 -0400 Subject: [PATCH 5/7] Fixing other heading --- website/src/pages/en/subgraphs/querying/distributed-systems.mdx | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/website/src/pages/en/subgraphs/querying/distributed-systems.mdx b/website/src/pages/en/subgraphs/querying/distributed-systems.mdx index 9460a8a6f5e0..7c3177a5a042 100644 --- a/website/src/pages/en/subgraphs/querying/distributed-systems.mdx +++ b/website/src/pages/en/subgraphs/querying/distributed-systems.mdx @@ -12,7 +12,7 @@ Whenever different computers are working together across the globe, certain prob A perfect example of this is the so-called "block wobble" phenomenon, where a client sees block data appear to jump forward and backward in unexpected ways. This phenomenon becomes especially noticeable during a block re-org — a situation where a previously ingested block is replaced by a different one under consensus. -#### Example of Block Reorganization +### Example of Block Reorganization To understand the impact, consider a scenario where a client continuously fetches the latest block from an Indexer: From dbc5f86e751b6899523eeeb746bdb1ad54c5a629 Mon Sep 17 00:00:00 2001 From: Michael Macaulay <56690114+MichaelMacaulay@users.noreply.github.com> Date: Fri, 30 May 2025 14:57:20 -0400 Subject: [PATCH 6/7] Update website/src/pages/en/subgraphs/querying/_meta.js MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit Co-authored-by: Benoît Rouleau --- website/src/pages/en/subgraphs/querying/_meta.js | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/website/src/pages/en/subgraphs/querying/_meta.js b/website/src/pages/en/subgraphs/querying/_meta.js index 0389427ddaee..65a221f3b664 100644 --- a/website/src/pages/en/subgraphs/querying/_meta.js +++ b/website/src/pages/en/subgraphs/querying/_meta.js @@ -6,7 +6,7 @@ export default { 'best-practices': '', 'from-an-application': '', 'distributed-systems': '', - 'distributed-systems-guide': '', + 'distributed-systems-guide': titles['distributed-systems-guide'] ?? '', 'graphql-api': '', 'subgraph-id-vs-deployment-id': '', 'graph-client': titles['graph-client'] ?? '', From f7470889dd025a76a279aa858dd48be03192ca88 Mon Sep 17 00:00:00 2001 From: Michael Macaulay Date: Fri, 30 May 2025 15:24:20 -0400 Subject: [PATCH 7/7] Fix --- .../pages/en/subgraphs/querying/distributed-systems-guide.mdx | 4 +--- 1 file changed, 1 insertion(+), 3 deletions(-) diff --git a/website/src/pages/en/subgraphs/querying/distributed-systems-guide.mdx b/website/src/pages/en/subgraphs/querying/distributed-systems-guide.mdx index ee675046c007..a0daa8d9924e 100644 --- a/website/src/pages/en/subgraphs/querying/distributed-systems-guide.mdx +++ b/website/src/pages/en/subgraphs/querying/distributed-systems-guide.mdx @@ -119,6 +119,4 @@ async function getDomainNames() { 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. -• 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. - -\[Placeholder for additional references or external resources if available\] +If you encounter re-orgs, plan to retry from the beginning or adjust your logic accordingly.