ndk icon indicating copy to clipboard operation
ndk copied to clipboard

fetchEvents doesn't handle offline relays correctly

Open chakany opened this issue 10 months ago • 3 comments

Incident

i've noticed that when using ndk's fetchEvents, if one of the explicit relay urls (eg, kitchen.zap.cooking) is offline, the fetch call hangs and an error message is logged to console. meanwhile, using subscribe works fine, even with the offline relay.

Details

testing with two configs:

  • config 1. both relays online
    • fetchEvents returns events as expected.
  • config 2: one relay (kitchen.zap.cooking) offline
    • fetchEvents hangs and errors out, but subscribe successfully receives events.

interestingly, when testing in node.js, there is no error message outputted even when wrapping in a try/catch. on node, the only error message is outputted if DEBUG='ndk:*' this behavior is the opposite on the web, even if the localStorage debug variable is blank, an error message is outputted after ~30 seconds.

How to reproduce

This is the node.js example i wrote. if the offline relay is set, it will hang. if it is commented out however, it works just fine.

fetchEvents example

const ndk = require("@nostr-dev-kit/ndk");
const WebSocket = require('ws');

global.WebSocket = WebSocket;

const nostr = new ndk.default({
  explicitRelayUrls: ["wss://relay.nostr.band",
    "wss://relay.google.com" // the "offline relay"
  ],
});

(async () => {
  try {
    await nostr.connect();
    console.log("connected");
    const sub = await nostr.fetchEvents({ kinds: [1] });
    console.log(sub);
  } catch (error) {
    console.error(error);
  }
})()

subscribe example

const ndk = require("@nostr-dev-kit/ndk");
const WebSocket = require('ws');

global.WebSocket = WebSocket;

const nostr = new ndk.default({
  explicitRelayUrls: ["wss://relay.nostr.band",
    "wss://relay.google.com" // the "offline relay"
  ],
});

(async () => {
  try {
    await nostr.connect();
    console.log("connected");
    const sub = nostr.subscribe({ kinds: [1] });
    sub.on("event", (event) => {
      console.log(`${event.content}`);
    });
  } catch (error) {
    console.error(error);
  }
})()

my guess is that fetchEvents isn't handling timeouts or errors correctly based on the console error behavior.

chakany avatar Feb 11 '25 13:02 chakany

looking at these 3 lines: https://github.com/nostr-dev-kit/ndk/blob/fdbe6e5934c431318f1f210fa9f797f40b53326c/ndk/src/ndk/index.ts#L705-L707

maybe the problem is that a subscription will only send back an eose if it receives events from all relays whether they are connected or not. since it never recieves an eose from an offline relay, maybe thats why it never resolves.

chakany avatar Feb 11 '25 14:02 chakany

I've been dealing with the same issues. I think https://github.com/nostr-dev-kit/ndk/issues/266 might be related.

3 days ago @pablof7z added this commit https://github.com/nostr-dev-kit/ndk/commit/05d16e1ce1c1cee8daf33fbb65f944a08d773633 which I wonder might be related.

Someone suggested that I add a timeout promise wrapper around fetchEvents with to catch this but that feels like a dirty fix.

Hope to spend time on this in the next days once I'm done with some other tasks

digitalbase avatar Mar 17 '25 10:03 digitalbase

The fix that I used was to just replace all fetchEvents with regular subscriptions

chakany avatar Mar 18 '25 13:03 chakany