BoundedExecutor

org.mbari.beholder.etc.jdk.BoundedExecutor
See theBoundedExecutor companion object
class BoundedExecutor(name: String, threads: Int, queueSize: Int, maxWait: Duration = ...) extends Executor

A fixed pool with a bounded queue, for work that must not be allowed to pile up without limit.

The alternative — Future on ExecutionContext.global — is a poor fit for shelling out to a subprocess. Its queue is unbounded, so a burst is accepted in full and the clients at the back have long since timed out by the time their work runs.

Here, saturation is visible instead. submit returns None rather than queueing without limit, which lets the caller shed load — an immediate "busy" is a better answer than a response nobody is waiting for any more.

This is a real java.util.concurrent.Executor, so it can be handed to anything that takes one — ExecutionContext.fromExecutor, CompletableFuture.supplyAsync, and so on.

maxWait allows the bounded queue to limit how much work is accepted; tasks are discarded if they wait too long for a worker rather than being run.

Value parameters

maxWait

How long a task may sit in the queue before a worker discards it rather than running it. Applies to submit only — see execute for why. Zero or negative means no deadline: queued work always runs, however long it waited.

name

Prefix for the worker thread names, so stack dumps say which pool is busy

queueSize

How many may wait

threads

How many tasks may run at once

Attributes

Companion
object
Graph
Supertypes
trait Executor
class Object
trait Matchable
class Any

Members list

Value members

Concrete methods

How many tasks have been discarded for waiting past maxWait instead of being run.

How many tasks have been discarded for waiting past maxWait instead of being run.

Worth watching: a number that climbs says the queue is deeper than the service can drain within the deadline, so either threads is too low for the arrival rate or queueSize is promising more than it can keep.

Attributes

override def execute(command: Runnable): Unit

Run command on this pool, per the java.util.concurrent.Executor contract: no handle on the result, and saturation reported by throwing rather than by a return value.

Run command on this pool, per the java.util.concurrent.Executor contract: no handle on the result, and saturation reported by throwing rather than by a return value.

A command that throws is left to the pool's usual handling. Callers that want the failure back, or that would rather shed load than catch, should use submit instead.

Note that maxWait is deliberately not applied here. Once accepted, a command always runs. Silently dropping it would break every wrapper built on this interface.

Attributes

Throws
java.util.concurrent.RejectedExecutionException

if every worker and queue slot is taken

Definition Classes
Executor
def queued: Int

How many tasks are waiting for a worker. Approximate — the queue moves while you read it.

How many tasks are waiting for a worker. Approximate — the queue moves while you read it.

Attributes

def shutdown(): Unit
def submit[A](body: => A): Option[Future[A]]

Run body on this pool.

Run body on this pool.

There are two ways this sheds load, and they are reported differently because they are known at different times. A full queue is known immediately, so it comes back as None. Having waited past maxWait is only known once a worker picks the task up, by which point the caller already holds a Future — so that arrives as a BoundedExecutor.StaleWorkException on the Future. Both mean the same thing to a caller: the work did not run and will not, because the service is over capacity.

Attributes

Returns

The eventual result, or None if the pool and its queue are both full. A body that throws fails the returned Future; it does not take the worker thread down with it.