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

Send a telemetry event on exit #541

Merged
merged 15 commits into from
Jan 16, 2024
Merged

Send a telemetry event on exit #541

merged 15 commits into from
Jan 16, 2024

Conversation

visnup
Copy link
Member

@visnup visnup commented Jan 13, 2024

Handles SIGINT, SIGHUP, and SIGTERM and sends an exiting telemetry event along with flushing its queue. Waits up to 1s to finish then exits no matter what. Doesn't install any signal listeners unless Telemetry.record is actually called, so nothing is sent on unwatched commands like help.

Sneaks in a few more data to track: node version and build page count.

Adds more test coverage of getPersistentId by moving the effect abstraction down to readFile and writeFile.

I'm a little wary of calling effects.process.exit inside of the signal handler since whatever's passed in may not actually exit which would hang the process. Maybe typescript will help since it'll enforce whatever is passed in for it has a never return type?

@visnup visnup requested review from mbostock and mythmon January 13, 2024 04:32
@visnup visnup enabled auto-merge (squash) January 13, 2024 05:09
@@ -18,39 +18,42 @@ describe("telemetry", () => {
setGlobalDispatcher(globalDispatcher);
});

const noopEffects = {env: {}, logger: new MockLogger(), getPersistentId: async () => randomUUID()};
const processMock = (mock: any) => Object.assign(Object.create(process), mock);
Copy link
Member Author

Choose a reason for hiding this comment

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

This was easy enough to write, but would it be worth it to bring in something like https://sinonjs.org for this stubbing and mocking?

Copy link
Member

@mythmon mythmon left a comment

Choose a reason for hiding this comment

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

If I wanted to write a test like "deploy sends the right telemetry", is there any way that I could wait for all telemetry to be sent? It seems like there is no way to wait for the pending queue to run before making tests assertions.

Comment on lines +137 to +141
if (!this._config) {
this._config = readFile(file, "utf8")
.then(JSON.parse)
.catch(() => ({}));
}
Copy link
Member

Choose a reason for hiding this comment

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

Something that we ran into in deploys is that treating all errors the same here can be confusing for the user. If the file doesn't exist returning {} is useful, but if there is a syntax error (like JSON.parse might throw), I think we should not treat it as a empty config.

One example I can think of: if I edit my config and make a syntax error (say, deleting a comma), then the next time this function runs it will delete my authorization information.

I think we should consider invalid syntax as an invalid config. Maybe that would mean returning null here? Or maybe even an error should be thrown to the user?

Copy link
Member Author

Choose a reason for hiding this comment

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

Ok, I think then in the case of JSON syntax error we just return null here then since I don't really want telemetry to be responsible for telling the user to fix a malformed configuration error. So if other code is using that same file, we'll hope/trust/cross-fingers that it'll raise a general issue about the file being malformed?

Copy link
Member Author

Choose a reason for hiding this comment

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

Egh, maybe we should consolidate ~/.observablehq file handling code though and just error. Because there are race condition dragons here.

src/telemetry.ts Outdated Show resolved Hide resolved
@visnup
Copy link
Member Author

visnup commented Jan 16, 2024

Awaiting a new record() at the end, even a stub-ish one, returns a Promise.all to the pending queue. So, it should get you what you want.

@visnup visnup force-pushed the visnup/telemetry-on-exit branch from e5ddb38 to c7dd255 Compare January 16, 2024 20:38
Copy link
Member

@mythmon mythmon left a comment

Choose a reason for hiding this comment

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

Thanks for the changes. I'm happy with this now, though I agree that unifying the ~/.observablehq loading would be good. That could be in this PR or another one, up to you.

assert.throws(() => {
new Telemetry({
...noopEffects,
process: processMock({env: {OBSERVABLE_TELEMETRY_ORIGIN: "☃️"}})
Copy link
Member

Choose a reason for hiding this comment

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

amazing

Copy link
Member Author

Choose a reason for hiding this comment

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

if I recall correctly, Rails used to force some http guarantees by submitting forms with ?utf8=☃ in a request param. it got changed pretty quickly to ?utf8=✓ to confuse/scare people less often. I dunno if that's still around anymore or how I'd even find it.

Copy link
Member Author

Choose a reason for hiding this comment

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

or maybe it was a heuristic to tell if a proxy or server in the middle of the request chain preserved it correctly all the way through?

Copy link
Member Author

Choose a reason for hiding this comment

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

ooh found it https://github.com/rails/rails/blob/473fd597f6ff8a575c36c565d205627fa7964a05/actionview/lib/action_view/helpers/form_tag_helper.rb#L910

now to figure out if my memory of it ever being a snowman value is correct or I'm combining two different memories…

Copy link
Member Author

Choose a reason for hiding this comment

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

thank you GitHub rails/rails@1cbe917

@visnup visnup merged commit 629353b into main Jan 16, 2024
2 checks passed
@visnup visnup deleted the visnup/telemetry-on-exit branch January 16, 2024 21:09
@visnup
Copy link
Member Author

visnup commented Jan 16, 2024

Going to work on consolidating ~/.observablehq handling code to handle any race conditions today. Will follow up with another PR… I also have a small change to add a the session index / id / handle thing, but realized I'd need to update the incoming endpoint to handle it first.

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.

3 participants