Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Cleanup setInterval in account fetch cache to avoid hanging Node process #651

Open
ChewingGlass opened this issue May 20, 2024 · 2 comments

Comments

@ChewingGlass
Copy link
Collaborator

ChewingGlass commented May 20, 2024

https://discord.com/channels/404106811252408320/1097632035155214567/1242201684487307384

@ke6jjj
Copy link
Contributor

ke6jjj commented May 20, 2024

I'll add context for those who can't click on the Discord link:

Summary

Calling getPendingRewards() in the @helium/distributor-oracle package appears to set up a background process that prevents nodejs from exiting when the current process/task is complete. On further investigation, the culprit appears to be an eternally repeating interval timer that is set up for an internal AccountFetchCache that is created using the singleton pattern.

To Reproduce

  1. Run any script which calls getPendingRewards. Example (Hotspot chosen at random):
import { init, lazyDistributorKey } from "@helium/lazy-distributor-sdk";
import { getPendingRewards, formTransaction } from "@helium/distributor-oracle";
import * as anchor from "@coral-xyz/anchor";
import { PublicKey } from "@solana/web3.js";
import {
    init as initHem,
    keyToAssetKey,
} from "@helium/helium-entity-manager-sdk";
import { daoKey } from "@helium/helium-sub-daos-sdk";
import { HNT_MINT } from "@helium/spl-utils";
import yargs from "yargs";

async function run (args: any = process.argv) {
    const yarg = yargs(args).options({
        wallet: {
            alias: "k",
            describe: "Anchor wallet keypair",
            type: "string",
            required: true,
        },
        url: {
            alias: "u",
            describe: "Solana RPC API endpoint",
            default: "https://api.mainnet-beta.solana.com",
        },
    });

    const argv = await yarg.argv;
    const hotspotB58 = "11F65cECrtEQksuH7HZQamRfGipL4xT4SX5anFy1uyw56Nmxe6h";

    process.env.ANCHOR_WALLET = argv.wallet;
    const providerConnection = anchor.AnchorProvider.local(argv.url);

    anchor.setProvider(providerConnection);
    const provider = anchor.getProvider() as anchor.AnchorProvider;
    const program = await init(provider);
    const hemProgram = await initHem(provider);

    const iotMintId = "iotEVVZLEywoTn1QdwNPddxPWszn3zFhEot3MfL9fns";
    const iotMint = new PublicKey(iotMintId);
    const hntMint = daoKey(HNT_MINT)[0];
    const lazyDistributorPkey = lazyDistributorKey(iotMint)[0];

    const [keyToAssetK] = keyToAssetKey(hntMint, hotspotB58);
    const keyToAsset = await hemProgram.account.keyToAssetV0.fetch(keyToAssetK);
    const asset = keyToAsset.asset;
    const rewards = getPendingRewards(program, lazyDistributorPkey, hntMint,
                [hotspotB58]);
    return rewards;
}

run().then(function (results) { console.log(results); });
  1. Notice that the script never exits, but instead hangs after printing the results.

Additional Info

Using the nifty package why-is-node-running (at https://github.com/mafintosh/why-is-node-running) one can see that there's a dangling timer still present at task completion:

# Timeout
...

./node_modules/@helium/account-fetch-cache/lib/cjs/accountFetchCache.js:81 - this.missingInterval = setInterval(this.fetchMissing.bind(this), missingRefetchDelay);
./node_modules/@helium/account-fetch-cache/lib/cjs/accountFetchCache.js:31 - singletons[endp + commitment] = new AccountFetchCache({
./node_modules/@helium/distributor-oracle/lib/cjs/client.js:66             - const cache = yield (0, account_fetch_cache_1.getSingleton)(hemProgram.provider.connection)

@ke6jjj
Copy link
Contributor

ke6jjj commented May 21, 2024

Workaround

While not stable in the long run, you can use process.exit(0); at the end of your script to force the process to exit.

The danger in using this method is that it is not a stable long-term pattern to use. This method could cause future versions of the code to perform badly if they spawn important subprocesses that need to complete before shutdown.

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment
Labels
None yet
Projects
None yet
Development

No branches or pull requests

2 participants