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

Cursor: avoid closing connection twice if error received after destroy() #2836

Merged
merged 5 commits into from
Mar 15, 2024

Conversation

alxndrsn
Copy link
Contributor

@alxndrsn alxndrsn commented Oct 6, 2022

Fix for #1674, alternative to #2832.

@alxndrsn alxndrsn marked this pull request as ready for review October 6, 2022 17:56
@brianc
Copy link
Owner

brianc commented Nov 21, 2022

Sorry for the delay here (things have been crazy over here recently). This looks good to me. If @charmander doesn't have any thoughts on the contrary I'm happy to merge & release this. Really appreciate your help & the test coverage!

@alxndrsn
Copy link
Contributor Author

Thanks @brianc - all feedback very appreciated 🙂

@alxndrsn
Copy link
Contributor Author

@brianc @charmander is there anything I can do to improve this PR?

@alxndrsn
Copy link
Contributor Author

Thanks @rafaell-lycan!

@nathanjcochran
Copy link

I am running into this issue as well (see my comment on #1674). I believe this PR would fix my problem. Would love to see this get merged!

@alxndrsn
Copy link
Contributor Author

I believe this PR would fix my problem.

@nathanjcochran I see you have a neat repro at #1674 (comment); any chance you can test this patch against that?

@nathanjcochran
Copy link

I see you have a neat repro at #1674 (comment); any chance you can test this patch against that?

@alxndrsn Just tested it, and it does indeed fix the issue! 🎉

@alxndrsn
Copy link
Contributor Author

@nathanjcochran Great news. Do you think your repro is significantly different from the test case in this PR? If so, should we consider turning it into an additional test case?

@nathanjcochran
Copy link

nathanjcochran commented May 26, 2023

@alxndrsn It does seem somewhat different, in that my repro is attempting to cancel the query (which triggers an error in the database for that query - I'm not entirely sure if the tests in this PR do that?), close the stream, and reuse that exact same connection without first returning it to the pool (whereas the tests in this PR seem to return the connection to the pool first). So I do think it could make sense to add a separate test case. Perhaps something like this (didn't actually have a change to test this yet - I don't have everything set up properly to run the tests locally at the moment):

it('should work after cancelling query', async () => {
  const pool = new pg.Pool();
  const conn = await pool.connect();

  // Get connection PID for sake of pg_cancel_backend() call
  const result = await conn.query('SELECT pg_backend_pid() AS pid;');
  const { pid } = result.rows[0];

  const stream = conn.query(new QueryStream('SELECT pg_sleep(10);'));
  stream.on('data', (chunk) => {
    // Switches stream into readableFlowing === true mode
  });
  stream.on('error', (err) => {
    // Errors are expected due to pg_cancel_backend() call
  });

  // Create a promise that is resolved when the stream is closed
  const closed = new Promise((res) => {
    stream.on('close', res);
  });

  // Wait 100ms before cancelling the query
  await new Promise((res) => {
    setTimeout(() => res(), 100);
  });

  // Cancel pg_sleep(10) query
  await pool.query('SELECT pg_cancel_backend($1);', [pid]);

  // Destroy stream and wait for it to be closed
  stream.destroy();
  await closed;

  // Subsequent query on same connection should succeed
  const res = await conn.query('SELECT 1 AS a;');
  assert.deepStrictEqual(res.rows, [ { a:1 } ]);
  
  conn.release()
  await pool.end()
})

@alxndrsn
Copy link
Contributor Author

Thanks @nathanjcochran - I'll give it a quick go. If the test is good, any objections to adding it to this PR?

@alxndrsn
Copy link
Contributor Author

@alxndrsn alxndrsn force-pushed the dont-close-cursor-twice branch from 63e1515 to eae0b69 Compare May 29, 2023 14:13
@alxndrsn
Copy link
Contributor Author

I've rebased this branch onto the latest master. Prior to that I confirmed that tests were still failing without the fix in packages/pg-cursor/index.js.

@nathanjcochran
Copy link

If the test is good, any objections to adding it to this PR?

@alxndrsn Go for it! Thank you!!

@alxndrsn
Copy link
Contributor Author

alxndrsn commented Jun 1, 2023

Thanks @nathanjcochran - added 👍

@alxndrsn
Copy link
Contributor Author

alxndrsn commented Jul 5, 2023

@brianc @charmander is there anything I can do to improve this PR? Very happy to discuss, or to close the PR if there is no interest in merging it.

@charmander
Copy link
Collaborator

I’d like to know why handleError is called after completion and haven’t looked into it yet.

(code style doesn’t match, by the way)

@alxndrsn
Copy link
Contributor Author

@charmander I'm happy to update the code style if that will help. Do you have any pointers on what would need to change?

@lognaturel
Copy link

lognaturel commented Sep 27, 2023

@charmander @brianc We've been running this in a fork for a year now and would really like to come back to mainline! Could one of you push the style changes that you want to this branch, maybe? 🙏

@alxndrsn
Copy link
Contributor Author

@charmander I've updated the formatting to mirror surrounding code; is it correct now?

@alxndrsn alxndrsn force-pushed the dont-close-cursor-twice branch from cd51583 to 5f5d42a Compare October 20, 2023 10:19
This reverts commit 5f5d42a.
@alxndrsn
Copy link
Contributor Author

I've rebased this branch onto master, and fixed all lint violations.

Interestingly two of the three new test cases now pass without the fix in this PR. From https://github.com/brianc/node-postgres/actions/runs/6586450194/job/17894838346?pr=2836:

  error recovery
    ✓ recovers from a streaming error in a transaction
    ✓ handles an error on a stream after a plain text non-stream error
    ✓ does not crash when closing a connection with a queued stream
    1) should work if used after timeout error
    ✓ should work if used after syntax error
    ✓ should work after cancelling query (112ms)

@alxndrsn
Copy link
Contributor Author

alxndrsn commented Mar 14, 2024

I've merged the latest master into this branch and the tests pass ✔️

I've also run the tests against latest master without the fix, and there are two failures:

  2 failing
  1) error recovery
       should work if used after timeout error:
      AssertionError [ERR_ASSERTION]: Input A expected to strictly deep-equal input B:
+ expected - actual
- []
+ [
+   {
+     d: 4
+   }
+ ]
      + expected - actual
      -[]
      +[
      +  {
      +    "d": 4
      +  }
      +]
      
      at /home/runner/work/node-postgres/node-postgres/packages/pg-query-stream/test/error.ts:109:12
      at Generator.next (<anonymous>)
      at fulfilled (test/error.ts:5:58)
      at process._tickCallback (internal/process/next_tick.js:68:7)
  2) error recovery
       should work after cancelling query:
      AssertionError [ERR_ASSERTION]: Input A expected to strictly deep-equal input B:
+ expected - actual
- []
+ [
+   {
+     a: 1
+   }
+ ]
      + expected - actual
      -[]
      +[
      +  {
      +    "a": 1
      +  }
      +]
      
      at /home/runner/work/node-postgres/node-postgres/packages/pg-query-stream/test/error.ts:168:12
      at Generator.next (<anonymous>)
      at fulfilled (test/error.ts:5:58)
      at process._tickCallback (internal/process/next_tick.js:68:7)

In addition, there seems to be some kind of shutdown problem when the fix is not included.

See: https://github.com/alxndrsn/node-postgres/actions/runs/8277192701/job/22647097080

alxndrsn pushed a commit to alxndrsn/node-postgres that referenced this pull request Mar 14, 2024
This should prevent runaway builds.

I noticed this issue when working on a fork of brianc#2836.  Example builds with/without these timeouts:

1. 6 hours: https://github.com/alxndrsn/node-postgres/actions/runs/8277192701
2. 10 minutes: https://github.com/alxndrsn/node-postgres/actions/runs/8277388503

These timeouts are 4-5x what a current healthy build takes.
@alxndrsn alxndrsn mentioned this pull request Mar 14, 2024
charmander pushed a commit that referenced this pull request Mar 15, 2024
This should prevent runaway builds.

I noticed this issue when working on a fork of #2836.  Example builds with/without these timeouts:

1. 6 hours: https://github.com/alxndrsn/node-postgres/actions/runs/8277192701
2. 10 minutes: https://github.com/alxndrsn/node-postgres/actions/runs/8277388503

These timeouts are 4-5x what a current healthy build takes.
@brianc
Copy link
Owner

brianc commented Mar 15, 2024

Thank you so much! Your help is amazing!

@brianc brianc merged commit 91de4b9 into brianc:master Mar 15, 2024
6 checks passed
@alxndrsn alxndrsn deleted the dont-close-cursor-twice branch March 17, 2024 06:20
@alessbelli
Copy link

This fix looks amazing, thank you for getting that over the finish line! I don't know what the general policy is here for cutting new tags, but I wondered when this would be tagged and published to npm as a new version? there hasn't been a new version in a while so I'd like to know whether it's best for us to wait for 8.12 or to use this commit.
Thanks again!

@brianc
Copy link
Owner

brianc commented Mar 30, 2024 via email

@brianc
Copy link
Owner

brianc commented Mar 30, 2024 via email

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.

7 participants