denoland/std

suggestion: `getAvailablePort()`

Closed this issue · 7 comments

Are any of the following utilities good candidates for inclusion?

withSignal

Run an async function by passing in a fresh abort controller's signal. Upon completion, abort.

Use case: ensuring that the resolution of a promise triggers the abort, which may trigger other things.

async function withSignal<T>(cb: (signal: AbortSignal) => Promise<T>) {
  const controller = new AbortController()
  try {
    return await cb(controller.signal)
  } finally {
    controller.abort()
  }
}

port.getAvailable

Determine an open port.

Use case: get an unused port when launching processes that allow for specificity of port.

function getAvailable(): number {
  const tmp = Deno.listen({ port: 0 })
  const { port } = tmp.addr as Deno.NetAddr
  tmp.close()
  return port
}

port.ready

Poll whether a given port can be connected to

Use case: determine whether a server is prepared to accept connections.

async function ready(port: number, ms = 500): Promise<void> {
  while (true) {
    try {
      const connection = await Deno.connect({ port })
      connection.close()
      break
    } catch (e) {
      if (e instanceof Deno.errors.ConnectionRefused) await delay(ms)
      else throw e
    }
  }
}

Although use cases are obvious if one has engaged in the related topics, I think an explainer is useful for each (and also that this is probably better-suited for a discussion topic than an issue).

I've just updated the description with use cases.

Regarding issue vs. discussion: it seems I'm unable to convert this issue into a discussion. Would someone with the necessary permissions please do so.

kt3k commented

I like getAvailable and ready ideas. I guess the module name might be std/net?

I don't see the use case of withSignal very well. Do you have any use case in mind?

I'm of a similar opinion. Yeah, I can't think of a use case for withSignal() right now.

PRs are welcome.

On second thought, I don't think these functions are the best approach.

Instead of using port.getAvailable(), one could just use port = 0, which automatically chooses a free port. Are there any use cases that defy that?

And instead of using port.ready() one could just use:

import { retry } from "https://deno.land/std@0.208.0/async/retry.ts";
await retry(async () => await Deno.connect({ port: 8000 }));

It's useful if someone needs to specify the port for other parts of a program before actually opening the connection. Good point re using retry.