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

ENG-2740 Use elapsed time for SSH retry timeout #124

Merged
merged 12 commits into from
Oct 4, 2024

Conversation

fabgo
Copy link
Contributor

@fabgo fabgo commented Oct 1, 2024

Use elapsed time to determine the SSH retry timeout instead of the number of retries.

Use elapsed time to determine the SSH retry timeout instead of the number of retries.
@fabgo fabgo requested a review from gergas3 October 1, 2024 23:13
Copy link
Contributor

@nbrahms nbrahms left a comment

Choose a reason for hiding this comment

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

My biggest concern is why we changed from a 30 second to 10 minute (!) timeout for AWS access.

*
* Each attempt consumes ~ 1 s.
/**
* It can take up to 1 minute for access to propagate on AWS, so set the time limit to 10 minutes.
Copy link
Contributor

@nbrahms nbrahms Oct 1, 2024

Choose a reason for hiding this comment

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

What's the motivation to change from 30 seconds to 10 minutes?

I'd be surprised if any end user is willing to wait 10 minutes.

Suggested change
* It can take up to 1 minute for access to propagate on AWS, so set the time limit to 10 minutes.
// It takes around 8 seconds for access to propagate on AWS, so allow 30 seconds as a safe ceiling.

Also, this should just be a normal comment as it's explaining why the value is chosen, rather than what it does.

Copy link
Contributor Author

@fabgo fabgo Oct 2, 2024

Choose a reason for hiding this comment

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

The timeout is based on existing comments in ssh/index.ts:

AWS takes about 8 minutes, GCP takes under 1 minute to fully resolve access after it is granted.
During this time, calls to aws ssm start-session / gcloud compute start-iap-tunnel
will fail randomly with an various error messages.

See also this PR, which also mentions 10 minutes: #19

Copy link
Contributor Author

Choose a reason for hiding this comment

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

@gergas3 @nbrahms I can change the timeout if you want. Just let me know what to set it to.

Copy link
Contributor

@gergas3 gergas3 Oct 3, 2024

Choose a reason for hiding this comment

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

Was it a typo in #19 then? I didn't observe such a long propagation time for AWS. 30 seconds makes more sense.

GCP takes significantly longer, it's mostly under 1 minute. But my guess would be it's not >99th percentile. We can continue with the 2m in this PR imo.

Copy link
Contributor Author

Choose a reason for hiding this comment

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

Changed it to 30 seconds.

Copy link
Contributor

Choose a reason for hiding this comment

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

The full info is that it takes AWS 30 minutes to get to 100% success rate. But we don't need to wait this long. We only need to wait until the chance that a single SSH attempt succeeds is high.

I'm not sure what we've changed in terms of delays, as those will affect this. But, when we were hammering it repeatedly in a loop, that took about 12 seconds.

*/
const MAX_SSH_RETRIES = 30;
const TIME_LIMIT_MS = 10 * 60 * 1000;
Copy link
Contributor

Choose a reason for hiding this comment

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

Suggested change
const TIME_LIMIT_MS = 10 * 60 * 1000;
const TIME_LIMIT_MS = 60 * 1000;

Seems already long enough.

When I analyzed this previously, 99% + of provisioning finished within 8 seconds. Has that changed?

*
* The length of each attempt varies based on the type of error from a few seconds to < 1s
/**
* It typically takes < 1 minute for access to propagate on GCP, so set the time limit to 2 minutes.
Copy link
Contributor

Choose a reason for hiding this comment

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

Would be good to understand the CDF of successful attempts by time.

print2(
`Waiting for access to propagate. ${gerund} SSH session... (remaining attempts: ${attemptsRemaining})`
);
print2(`Waiting for access to propagate. ${gerund} SSH session...)`);
Copy link
Contributor

Choose a reason for hiding this comment

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

Seems like we should display

Suggested change
print2(`Waiting for access to propagate. ${gerund} SSH session...)`);
const remainingS = ((endTime - Date.now()) / 1e3 ).toFixed(1)
print2(`Waiting for access to propagate. ${gerund} SSH session... (will wait up to ${remainingS} seconds)`);

Copy link
Contributor Author

Choose a reason for hiding this comment

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

Done

src/types/ssh.ts Outdated
@@ -80,6 +80,8 @@ export type SshProvider<

/** Unwraps this provider's types */
requestToSsh: (request: CliPermissionSpec<PR, O>) => SR;

timeLimit: number;
Copy link
Contributor

Choose a reason for hiding this comment

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

This should have some jsdoc describing what it does. I might also suggest giving it a more descriptive name:

Suggested change
timeLimit: number;
/** Amount of time, in ms, to wait between granting access and giving up on attempting an SSH connection */
propagationTimeoutMs: number;

Copy link
Contributor Author

Choose a reason for hiding this comment

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

Done

Copy link
Contributor

@gergas3 gergas3 left a comment

Choose a reason for hiding this comment

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

With this change does this check in plugins/ssh/index.ts:

    if (
      match &&
      Date.now() <=
        beforeStart + (match.validationWindowMs || DEFAULT_VALIDATION_WINDOW_MS)
    ) {
      isEphemeralAccessDeniedException = true;
    }

still make sense? Do we want to have a timeout on individual subprocesses and consider the error non-ephemeral if we read it off the stderr too late.

I think it can be removed or set to a larger value because we have an overall cap on the time.

@@ -398,6 +394,6 @@ export const sshOrScp = async (args: {
stdio: ["inherit", "inherit", "pipe"],
debug: cmdArgs.debug,
provider: request.type,
attemptsRemaining: sshProvider.maxRetries,
endTime: Date.now() + sshProvider.propagationTimeoutMs,
Copy link
Contributor

Choose a reason for hiding this comment

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

To globally wait max propagationTimeoutMs, we would have to the endTime once before calling preTestAccessPropagationIfNeeded (above), and pass the same endTime to spawnSshNode (here).

Now for a GCP sudo access the total propagationTimeoutMs is 2m * 2.

Copy link
Contributor Author

Choose a reason for hiding this comment

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

Done

@fabgo fabgo merged commit d0e583c into main Oct 4, 2024
3 checks passed
@fabgo fabgo deleted the fabian/eng-2740-ssh-use-elapsed-time branch October 4, 2024 15:45
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