telega/polling

Long polling implementation for Telegram Bot API.

This module provides long polling as an alternative to webhooks for receiving updates. A polling worker actor continuously fetches updates from Telegram and dispatches them to the bot’s message handlers.

Supervised mode (recommended)

When using telega.init_for_polling(), the polling worker is automatically started inside the supervision tree as a Permanent child. No manual setup is needed:

let assert Ok(_bot) =
  telega.new_for_polling(token: "BOT_TOKEN")
  |> telega.with_router(router)
  |> telega.init_for_polling_nil_session()

process.sleep_forever()

Use telega.with_polling_config() on the builder to customize timeout, limit, and poll interval before calling init_for_polling().

Manual mode

For advanced use cases (custom offsets, separate lifecycle management), start polling manually:

let assert Ok(poller) =
  polling.start_polling_default(
    client: telega.get_api_config(bot),
    bot: telega.get_bot_subject_internal(bot),
  )

Error handling

The polling worker uses exponential backoff for transient errors (network issues, rate limits, server errors). Critical errors (invalid token, bot deleted, or 10+ consecutive failures) stop polling and invoke the optional on_stop callback.

Types

Opaque type representing a running poller instance

pub opaque type Poller

Status of the poller

pub type PollerStatus {
  Starting
  Running
  Stopped
  Failed(String)
}

Constructors

  • Starting
  • Running
  • Stopped
  • Failed(String)

Messages for the polling worker actor

pub type PollingMessage {
  StartPolling(offset: option.Option(Int))
  StopPolling
  PollNext(offset: Int)
  InjectUpdates(updates: List(types.Update), offset: Int)
  SetSelf(subject: process.Subject(PollingMessage))
  HandleError(error: error.TelegaError, offset: Int)
}

Constructors

Values

pub fn calculate_new_offset(
  updates: List(types.Update),
  current_offset: Int,
) -> Int

Calculate the next offset based on received updates

pub fn get_config_info(
  poller: Poller,
) -> #(Int, Int, List(String), Int)

Get the polling configuration metadata

pub fn get_status(poller: Poller) -> PollerStatus

Get the current status of the poller

pub fn is_running(poller: Poller) -> Bool

Check if poller is running

pub fn start_polling(
  client client: client.TelegramClient,
  bot bot: process.Subject(bot.BotMessage),
  timeout timeout: Int,
  limit limit: Int,
  allowed_updates allowed_updates: List(String),
  poll_interval poll_interval: Int,
) -> Result(Poller, error.TelegaError)

Start polling with the given client and bot subject.

pub fn start_polling_default(
  client client: client.TelegramClient,
  bot bot: process.Subject(bot.BotMessage),
) -> Result(Poller, error.TelegaError)

Start polling with default configuration.

pub fn start_polling_with_notify(
  client client: client.TelegramClient,
  bot bot: process.Subject(bot.BotMessage),
  timeout timeout: Int,
  limit limit: Int,
  allowed_updates allowed_updates: List(String),
  poll_interval poll_interval: Int,
  on_stop on_stop: fn(error.TelegaError) -> Nil,
) -> Result(Poller, error.TelegaError)

Start polling with a notification callback for when polling stops due to errors. The callback will be invoked with the error that caused polling to stop.

pub fn start_polling_with_offset(
  client client: client.TelegramClient,
  bot bot: process.Subject(bot.BotMessage),
  offset offset: Int,
  timeout timeout: Int,
  limit limit: Int,
  allowed_updates allowed_updates: List(String),
  poll_interval poll_interval: Int,
) -> Result(Poller, error.TelegaError)

Start polling with a custom offset.

pub fn stop(poller: Poller) -> Nil

Stop polling

pub fn stop_worker(
  worker worker: process.Subject(PollingMessage),
) -> Nil

Stop a supervised polling worker by its subject.

Sends StopPolling, which makes the worker stop fetching new updates after its current batch. Used by graceful shutdown to halt intake before draining.

pub fn supervised(
  client client: client.TelegramClient,
  bot bot: process.Subject(bot.BotMessage),
  timeout timeout: Int,
  limit limit: Int,
  allowed_updates allowed_updates: List(String),
  poll_interval poll_interval: Int,
  on_stop on_stop: option.Option(fn(error.TelegaError) -> Nil),
  name name: process.Name(PollingMessage),
) -> supervision.ChildSpecification(
  process.Subject(PollingMessage),
)

Create a ChildSpecification for running polling inside a supervision tree. The polling worker will automatically delete the webhook and start polling.

pub fn wait_finish(poller: Poller) -> Nil

Wait for the poller to finish This function blocks indefinitely until the polling worker stops

Search Document