Nostrum Documentation
repository·master·Indexed 20 days ago
https://github.com/kraigie/nostrumAn Elixir library for interacting with the Discord API. It features a REST implementation, automatic local data caching, and support for multi-node distribution and live bot migration. Key capabilities include implementing the Nostrum.Consumer behaviour, manual sharding via Nostrum.Shard.Supervisor, Zstd gateway compression, and high availability using OTP distributed applications.
What's inside Nostrum
- Nostrum provides modules to interface directly with Erlang when necessary. This is primarily used to leverage the QLC (Query Logically Compiled) query compiler and its associated optimizations within the Nostrum environment.
Understand the purpose of Nostrum benchmarks
masterThebenchmarks/directory contains microbenchmarks designed to validate the performance of Nostrum components, with a primary focus on its cache implementations. These benchmarks are intended to push the caching backends to their limits to identify potential performance bottlenecks or issues under heavy load.Handle Application Takeover Events
masterWhen running in a distributed high-availability setup, your application's
def startfunction receives atypeargument that indicates how the node was started:{:failover, source_node}: The node was started because thesource_nodefailed.{:takeover, source_node}: The node is taking over from thesource_node(typically used when a failed node restarts).
You can use these types to trigger specific logic, such as re-registering commands or re-initializing state.
How Nostrum handles API abstractions and helpers
masterNostrum provides high-level helpers for certain Discord API endpoints to simplify common tasks. For example, while the standard Discord API limits message retrieval to 100 messages per request, the
Nostrum.Api.Channel.messages/3helper automatically handles pagination to retrieve any requested number of messages.Method names in the
Nostrum.Apisubmodules are designed to match Discord's official documentation closely to make it easier to cross-reference endpoints.# Example of a helper abstraction (conceptual) Nostrum.Api.Channel.messages(channel_id, limit, options)How encryption modes affect performance
masterDifferent encryption modes have different performance characteristics based on your hardware and implementation:
:aes256_gcm(Default): Leverages Erlang's:cryptomodule and is highly efficient on CPUs with AES hardware acceleration. This is the recommended default.xchacha20_poly1305: Uses the:cryptomodule'schacha20_poly1305AEAD cipher. This may perform better than AES on hardware that lacks AES acceleration.xsalsa20_poly1305: The Salsa20/XSalsa20 cipher is implemented in Elixir (with Poly1305 handled by:crypto), making these modes generally the slowest.
How different cache implementations work in Nostrum
masterNostrum provides several caching strategies depending on your bot's scale and requirements:
ETS Caching (Default)
- Usage: No configuration required; it is the default.
- Pros: Fast and light on memory.
- Cons: Does not support distribution or secondary indexing. Custom queries may result in full table scans.
- Best for: Smaller bots.
Mnesia Caching
- Usage: Suggested for larger bots requiring cache distribution, fragmentation, or secondary indexing.
- Requirements:
mnesiamust be available and installed with OTP (may not be available on Nerves).- Mnesia must be started ahead of Nostrum.
- Features: Tables are created automatically at startup. You can use the
table/0function to retrieve the table name for schema operations like adding replicas or fragmentation. - Consistency: Access is performed in
sync_transactionmode.
NoOp Caching
- Usage: Use the
NoOpadapters when you do not want to cache specific data from Discord at all.
Configure audio timeout and burst settings
masterAudio Timeout
When invoking
Nostrum.Voice.play/4, the player has an initial window to generate audio before timing out.- Default:
20_000ms (20 seconds). - Post-start: Once audio begins transmitting, the timeout drops to
500ms. - Use Case: If you are playing large files with significant seek times (e.g., via
:ytdl), you may need to increase the timeout. If you need faster error detection for small files, you can decrease it.
Audio Frames Per Burst
Nostrum collects opus frames and sends them in a "burst" to reduce overhead.
- Default:
:audio_frames_per_burstis10(equivalent to 200ms of audio). - Important: If you attempt to play audio shorter than 200ms, it will time out because it is waiting to collect 10 frames. To play very short clips, set
:audio_frames_per_burstto a lower value, such as1.
- Default:
Manage internal state via Nostrum.Store
masterNostrum's mandatory internal state is handled by modules located in theNostrum.Storenamespace. Unlike caches, which can be swapped for aNoOpimplementation, internal state is required for the library to operate and follows a similar pluggable pattern to the caching system.Understand cache invalidation and expiration in Nostrum
masterNostrum's cache invalidation behavior depends on the implementation:
- General Behavior: Most caches are maintained in response to Gateway events (e.g., deleting a guild and its members when leaving a guild). Nostrum does not regularly prune caches or associate expiration times with entries.
- Custom Implementations: If you implement a cache backend that persists to disk, you are responsible for managing expiration and pruning.
- Exception (
Nostrum.Cache.MessageCache.Mnesia): This specific implementation includes automatic management:- It has a default size limit of 10,000 messages.
- When the limit is reached, it automatically removes the 100 oldest messages.
- It deletes all cached messages for a channel when that channel is deleted.
How ratelimiting works in Nostrum
masterRatelimiting is managed internally by Nostrum to ensure compliance with Discord's limits. To benefit from automatic ratelimit handling, you must use one of the following:
- The specific methods provided in the
Nostrum.Apisubmodules. - The generic
Nostrum.Api.request/4function.
All requests are funneled through the
Nostrum.Api.Ratelimiterstate machine, which ensures that requests are handled correctly whether they are called synchronously or asynchronously.- The specific methods provided in the
How event handling works in Nostrum
masterNostrum handles interactions from Discord via a websocket connection by dispatching events to consumers. When an event occurs (e.g., a message is created or a channel is deleted), Nostrum dispatches that event to:
- The primary consumer configured via
Nostrum.Bot.bot_options/0. - Any processes listening via
Nostrum.ConsumerGroup.
Events are dispatched to these consumers after they have been ingested into the cache.
Nostrum.ConsumerGroupallows for dynamic subscriptions at runtime, which can function across different nodes in a cluster.- The primary consumer configured via
Understand the difference between Caches and State in Nostrum
masterNostrum manages data through two distinct mechanisms:
- Caches: Optional layers used to provide your bot with fresh, accessible data. By default, these use Erlang's ETS tables. You can replace these with custom implementations (e.g., for external caching or distributed nodes).
- State: Mandatory internal state required for Nostrum to function properly. This is managed via modules under
Nostrum.Storeand cannot be disabled via aNoOpimplementation like caches can.