Poller class

A class that represents the definition of a program that polls through consecutive requests until it reaches a state of completion.

A poller can be executed manually, by polling request by request by calling to the poll() method repeatedly, until its operation is completed. It also provides a way to wait until the operation completes, by calling pollUntilDone() and waiting until the operation finishes. Pollers can also request the cancellation of the ongoing process to whom is providing the underlying long running operation.

const poller = new MyPoller();

// Polling just once:
await poller.poll();

// We can try to cancel the request here, by calling:
//
//     await poller.cancelOperation();
//

// Getting the final result:
const result = await poller.pollUntilDone();

The Poller is defined by two types, a type representing the state of the poller, which must include a basic set of properties from PollOperationState<TResult>, and a return type defined by TResult, which can be anything.

The Poller class implements the PollerLike interface, which allows poller implementations to avoid having to export the Poller's class directly, and instead only export the already instantiated poller with the PollerLike type.

class Client {
  public async makePoller: PollerLike<MyOperationState, MyResult> {
    const poller = new MyPoller({});
    // It might be preferred to return the poller after the first request is made,
    // so that some information can be obtained right away.
    await poller.poll();
    return poller;
  }
}

const poller: PollerLike<MyOperationState, MyResult> = myClient.makePoller();

A poller can be created through its constructor, then it can be polled until it's completed. At any point in time, the state of the poller can be obtained without delay through the getOperationState method. At any point in time, the intermediate forms of the result type can be requested without delay. Once the underlying operation is marked as completed, the poller will stop and the final value will be returned.

const poller = myClient.makePoller();
const state: MyOperationState = poller.getOperationState();

// The intermediate result can be obtained at any time.
const result: MyResult | undefined = poller.getResult();

// The final result can only be obtained after the poller finishes.
const result: MyResult = await poller.pollUntilDone();

Constructors

Poller<TState, TResult>(PollOperation<TState, TResult>)

A poller needs to be initialized by passing in at least the basic properties of the PollOperation<TState, TResult>.

When writing an implementation of a Poller, this implementation needs to deal with the initialization of any custom state beyond the basic definition of the poller. The basic poller assumes that the poller's operation has already been defined, at least its basic properties. The code below shows how to approach the definition of the constructor of a new custom poller.

export class MyPoller extends Poller<MyOperationState, string> {
  constructor({
    // Anything you might need outside of the basics
  }) {
    let state: MyOperationState = {
      privateProperty: private,
      publicProperty: public,
    };

    const operation = {
      state,
      update,
      cancel,
      toString
    }

    // Sending the operation to the parent's constructor.
    super(operation);

    // You can assign more local properties here.
  }
}

Inside of this constructor, a new promise is created. This will be used to tell the user when the poller finishes (see pollUntilDone()). The promise's resolve and reject methods are also used internally to control when to resolve or reject anyone waiting for the poller to finish.

The constructor of a custom implementation of a poller is where any serialized version of a previous poller's operation should be deserialized into the operation sent to the base constructor. For example:

export class MyPoller extends Poller<MyOperationState, string> {
  constructor(
    baseOperation: string | undefined
  ) {
    let state: MyOperationState = {};
    if (baseOperation) {
      state = {
        ...JSON.parse(baseOperation).state,
        ...state
      };
    }
    const operation = {
      state,
      // ...
    }
    super(operation);
  }
}

Methods

cancelOperation({ abortSignal?: AbortSignalLike })

Attempts to cancel the underlying operation.

It only optionally receives an object with an abortSignal property, from @azure/abort-controller's AbortSignalLike.

If it's called again before it finishes, it will throw an error.

getOperationState()

Returns the state of the operation.

Even though TState will be the same type inside any of the methods of any extension of the Poller class, implementations of the pollers can customize what's shared with the public by writing their own version of the getOperationState method, and by defining two types, one representing the internal state of the poller and a public type representing a safe to share subset of the properties of the internal state. Their definition of getOperationState can then return their public type.

Example:

// Let's say we have our poller's operation state defined as:
interface MyOperationState extends PollOperationState<ResultType> {
  privateProperty?: string;
  publicProperty?: string;
}

// To allow us to have a true separation of public and private state, we have to define another interface:
interface PublicState extends PollOperationState<ResultType> {
  publicProperty?: string;
}

// Then, we define our Poller as follows:
export class MyPoller extends Poller<MyOperationState, ResultType> {
  // ... More content is needed here ...

  public getOperationState(): PublicState {
    const state: PublicState = this.operation.state;
    return {
      // Properties from PollOperationState<TResult>
      isStarted: state.isStarted,
      isCompleted: state.isCompleted,
      isCancelled: state.isCancelled,
      error: state.error,
      result: state.result,

      // The only other property needed by PublicState.
      publicProperty: state.publicProperty
    }
  }
}

You can see this in the tests of this repository, go to the file: ../test/utils/testPoller.ts and look for the getOperationState implementation.

getResult()

Returns the result value of the operation, regardless of the state of the poller. It can return undefined or an incomplete form of the final TResult value depending on the implementation.

isDone()

Returns true if the poller has finished polling.

isStopped()

Returns true if the poller is stopped.

onProgress((state: TState) => void)

Invokes the provided callback after each polling is completed, sending the current state of the poller's operation.

It returns a method that can be used to stop receiving updates on the given callback function.

poll({ abortSignal?: AbortSignalLike })

Returns a promise that will resolve once a single polling request finishes. It does this by calling the update method of the Poller's operation.

It only optionally receives an object with an abortSignal property, from @azure/abort-controller's AbortSignalLike.

pollUntilDone({ abortSignal?: AbortSignalLike })

Returns a promise that will resolve once the underlying operation is completed.

stopPolling()

Stops the poller from continuing to poll.

toString()

Returns a serialized version of the poller's operation by invoking the operation's toString method.

Constructor Details

Poller<TState, TResult>(PollOperation<TState, TResult>)

A poller needs to be initialized by passing in at least the basic properties of the PollOperation<TState, TResult>.

When writing an implementation of a Poller, this implementation needs to deal with the initialization of any custom state beyond the basic definition of the poller. The basic poller assumes that the poller's operation has already been defined, at least its basic properties. The code below shows how to approach the definition of the constructor of a new custom poller.

export class MyPoller extends Poller<MyOperationState, string> {
  constructor({
    // Anything you might need outside of the basics
  }) {
    let state: MyOperationState = {
      privateProperty: private,
      publicProperty: public,
    };

    const operation = {
      state,
      update,
      cancel,
      toString
    }

    // Sending the operation to the parent's constructor.
    super(operation);

    // You can assign more local properties here.
  }
}

Inside of this constructor, a new promise is created. This will be used to tell the user when the poller finishes (see pollUntilDone()). The promise's resolve and reject methods are also used internally to control when to resolve or reject anyone waiting for the poller to finish.

The constructor of a custom implementation of a poller is where any serialized version of a previous poller's operation should be deserialized into the operation sent to the base constructor. For example:

export class MyPoller extends Poller<MyOperationState, string> {
  constructor(
    baseOperation: string | undefined
  ) {
    let state: MyOperationState = {};
    if (baseOperation) {
      state = {
        ...JSON.parse(baseOperation).state,
        ...state
      };
    }
    const operation = {
      state,
      // ...
    }
    super(operation);
  }
}
new Poller(operation: PollOperation<TState, TResult>)

Parameters

operation

PollOperation<TState, TResult>

Must contain the basic properties of PollOperation<State, TResult>.

Method Details

cancelOperation({ abortSignal?: AbortSignalLike })

Attempts to cancel the underlying operation.

It only optionally receives an object with an abortSignal property, from @azure/abort-controller's AbortSignalLike.

If it's called again before it finishes, it will throw an error.

function cancelOperation(options?: { abortSignal?: AbortSignalLike }): Promise<void>

Parameters

options

{ abortSignal?: AbortSignalLike }

Optional properties passed to the operation's update method.

Returns

Promise<void>

getOperationState()

Returns the state of the operation.

Even though TState will be the same type inside any of the methods of any extension of the Poller class, implementations of the pollers can customize what's shared with the public by writing their own version of the getOperationState method, and by defining two types, one representing the internal state of the poller and a public type representing a safe to share subset of the properties of the internal state. Their definition of getOperationState can then return their public type.

Example:

// Let's say we have our poller's operation state defined as:
interface MyOperationState extends PollOperationState<ResultType> {
  privateProperty?: string;
  publicProperty?: string;
}

// To allow us to have a true separation of public and private state, we have to define another interface:
interface PublicState extends PollOperationState<ResultType> {
  publicProperty?: string;
}

// Then, we define our Poller as follows:
export class MyPoller extends Poller<MyOperationState, ResultType> {
  // ... More content is needed here ...

  public getOperationState(): PublicState {
    const state: PublicState = this.operation.state;
    return {
      // Properties from PollOperationState<TResult>
      isStarted: state.isStarted,
      isCompleted: state.isCompleted,
      isCancelled: state.isCancelled,
      error: state.error,
      result: state.result,

      // The only other property needed by PublicState.
      publicProperty: state.publicProperty
    }
  }
}

You can see this in the tests of this repository, go to the file: ../test/utils/testPoller.ts and look for the getOperationState implementation.

function getOperationState(): TState

Returns

TState

getResult()

Returns the result value of the operation, regardless of the state of the poller. It can return undefined or an incomplete form of the final TResult value depending on the implementation.

function getResult(): undefined | TResult

Returns

undefined | TResult

isDone()

Returns true if the poller has finished polling.

function isDone(): boolean

Returns

boolean

isStopped()

Returns true if the poller is stopped.

function isStopped(): boolean

Returns

boolean

onProgress((state: TState) => void)

Invokes the provided callback after each polling is completed, sending the current state of the poller's operation.

It returns a method that can be used to stop receiving updates on the given callback function.

function onProgress(callback: (state: TState) => void): CancelOnProgress

Parameters

callback

(state: TState) => void

Returns

poll({ abortSignal?: AbortSignalLike })

Returns a promise that will resolve once a single polling request finishes. It does this by calling the update method of the Poller's operation.

It only optionally receives an object with an abortSignal property, from @azure/abort-controller's AbortSignalLike.

function poll(options?: { abortSignal?: AbortSignalLike }): Promise<void>

Parameters

options

{ abortSignal?: AbortSignalLike }

Optional properties passed to the operation's update method.

Returns

Promise<void>

pollUntilDone({ abortSignal?: AbortSignalLike })

Returns a promise that will resolve once the underlying operation is completed.

function pollUntilDone(pollOptions?: { abortSignal?: AbortSignalLike }): Promise<TResult>

Parameters

pollOptions

{ abortSignal?: AbortSignalLike }

Returns

Promise<TResult>

stopPolling()

Stops the poller from continuing to poll.

function stopPolling()

toString()

Returns a serialized version of the poller's operation by invoking the operation's toString method.

function toString(): string

Returns

string