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

Fix the awaitable collect() calls. #638

Open
wants to merge 1 commit into
base: master
Choose a base branch
from

Conversation

farcaller
Copy link

In case if non-native promises are used, the Promise object won't be instanceof Promise. That's still valid in JS, as Promise is something that implements then(). It's always safe to cast a maybe-promise into native Promise with Promise.resolve().

Copy link
Collaborator

@zbjornson zbjornson left a comment

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Is anyone actually using non-native promises now? They've been available in Node since Feb 2015 and this library requires native Promise support. I'm kind of inclined to say we shouldn't make this change and should instead tell users implementing custom collect() functions to return a native Promise.

lib/counter.js Outdated
@@ -108,8 +108,7 @@ class Counter extends Metric {

async get() {
if (this.collect) {
const v = this.collect();
if (v instanceof Promise) await v;
const v = await Promise.resolve(this.collect());
Copy link
Collaborator

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

The original code was intended to avoid entering the microtask queue unless necessary, for performance (i.e. don't await unless necessary).

What about duck-typing for a thenable?

Copy link
Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

That's an interesting point I didn't consider. I suppose duck-typing is fair. Updated the PR.

@farcaller
Copy link
Author

Is anyone actually using non-native promises now?

Funnily, yes. ClojureScript's Promesa uses non-native Promises (and that's how I ended up going down this rabbit hole).

@zbjornson
Copy link
Collaborator

What do you think about doing this on the consumer side though? i.e. in your custom collect() function, return Promise.resolve(/*the Promesa promise */).

@farcaller
Copy link
Author

That's what I'm doing right now. I think it's just a bit of an unexpected behavior from the library to say it takes a promise, but then actually taking a very specific-exactly-JSPromise promise.

I guess, it holds true for the 95% promises flying around, though? Maybe it's worthwhile to mention it in the docs then, to not incur the runtime costs.

@farcaller
Copy link
Author

I'm giving this another thought and I wonder: is this actually the use case where the code must be extremely performant? I'd expect that metrics page would be scraped once in a while, or pushed once in a while, where "a while" is dozens of seconds. At that scale, optimizing for microtask scheduling seems a bit futile, is it not?

@zbjornson
Copy link
Collaborator

is this actually the use case where the code must be extremely performant?

prom-client gets a surprising number of PRs to improve its performance. I think it's valid to want observability frameworks to be as low of overhead as possible. If you have 100s of metrics with collect() functions, that could have an impact.

I'm +1 on a doc-only change that says the return type needs to be a native Promise. The typescript types are already correct fwiw: they say Promise and not PromiseLike.

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

Successfully merging this pull request may close these issues.

2 participants