For the complete documentation index, see llms.txt. This page is also available as Markdown.

Glossary

Reference · Applies to Brighter V10 and Darker V4

This glossary provides definitions for key terms used in Brighter and Darker. Terms are organized by category for easy navigation.

Core Concepts

Request

A message sent over a bus. The base type for Commands, Events, and Queries. A Request represents an instruction or notification that needs to be processed by a handler.

See: Implementing Command, Events and Queries

Command

An instruction to execute some behavior that may update state. Commands are imperative - they tell the system to do something. A command should have one handler.

Example: AddGreeting, DeletePerson, UpdateOrder

See: Basic Configuration

Event

A notification that something has happened. Events are facts about the past. Multiple handlers can subscribe to an event. Events do not update state directly - they inform interested parties about state changes that have already occurred.

Example: GreetingMade, PersonDeleted, OrderPlaced

See: Publishing Events

Query

A request for data that does not update state. Queries are processed by the Query Processor (Darker). A query returns a Result. Queries implement IQuery<TResult> where TResult is the type of data returned.

Example: GetPersonNameQuery, GetOrderDetailsQuery, SearchProductsQuery

See: Queries and Query Objects, CQRS with Brighter and Darker

Result

The value a Query returns. A Query Handler produces the Result and the Query Processor hands it back to the caller; a Query declares the type it returns by implementing IQuery<TResult>.

See: Query Result Types

Query Object

A pattern where query parameters are encapsulated in an object that implements IQuery<TResult>. The Query Object pattern separates the definition of a query from its execution, enabling middleware pipelines and testability.

See: Queries and Query Objects

Query Handler

A class that executes a query and returns results. Query handlers contain the logic for retrieving and projecting data. Handlers derive from QueryHandler<TQuery, TResult> (synchronous) or QueryHandlerAsync<TQuery, TResult> (asynchronous).

See: Implementing a Query Handler

Query Pipeline

A chain of decorators (middleware) that wrap a query handler to provide cross-cutting concerns like logging, retry, circuit breakers, and fallback policies. Similar to Brighter's request pipeline but optimized for read operations.

See: Query Pipeline and Decorators

Query Decorator

A middleware component that wraps query handlers to add cross-cutting functionality. Common decorators include QueryLogging, RetryableQuery, and FallbackPolicy.

See: Query Pipeline and Decorators

Command-Query Separation (CQS)

The principle that a method either changes state or reports it, never both, so a Query never has the side-effect of an update. Brighter handles the Commands and Events that change state and Darker the Queries that report it: the split between the two frameworks is this principle made structural.

See: CQRS with Brighter and Darker

Processors

Command Processor

The component that sends and publishes Commands and Events. The Command Processor provides middleware functionality like retry, logging, and timeouts through a pipeline. It separates the sender from the receiver.

Interface: IAmACommandProcessor

See: How the Command Processor Works

Query Processor

The component that executes Queries and returns Results. The Query Processor provides middleware functionality similar to the Command Processor, including logging, retry, and fallback policies. Part of Darker. The Query Processor dispatches queries to query handlers through a pipeline of decorators.

Interface: IQueryProcessor

See: Darker Basic Configuration, Query Pipeline and Decorators

Brighter and Darker Terms

Brighter

The framework for Commands and Events - messages that may update state. Brighter provides both in-process and out-of-process messaging capabilities.

See: Show me the code!

Darker

The framework for Queries - messages that return data without updating state. Darker follows the same patterns as Brighter (handlers, pipelines, policies) but is optimized for read operations. Darker implements the Query Object pattern and provides decorators for logging, retry, circuit breakers, and fallback.

See: Darker Basic Configuration, CQRS with Brighter and Darker

Dispatcher and Consumers

Dispatcher

The component that listens for messages from external middleware (like RabbitMQ or Kafka) and dispatches them to handlers. The Dispatcher is the runtime component that processes messages from a queue or topic.

Note: The assembly name is Paramore.Brighter.ServiceActivator, but the concept and class are referred to as "Dispatcher" throughout the documentation.

See: How the Dispatcher Works

Consumer

A Dispatcher that listens to external messages from middleware and forwards them to handlers. Configured using subscriptions.

See: Configuring the Dispatcher

ServiceActivator

The assembly name for the Dispatcher component (Paramore.Brighter.ServiceActivator). When referring to the concept or runtime behavior, use "Dispatcher" instead.

Handler & Pipeline

Handler

A class that processes a Request (Command, Event, or Query). Handlers contain the business logic for responding to requests.

Interface: IHandleRequests<T> (synchronous) or IHandleRequestsAsync<T> (asynchronous)

See: Implementing a Handler

Request Handler

The specific interface for handling requests. Handlers derive from RequestHandler<T> or RequestHandlerAsync<T>.

See: Request Handlers and Pipelines

Pipeline

A chain of handlers with middleware that processes a request. The pipeline allows you to compose cross-cutting concerns (logging, retry, validation) around your business logic.

See: Building a Pipeline

Middleware

A handler that wraps other handlers to provide cross-cutting functionality. Middleware handlers run before and/or after the main handler. Common middleware includes logging, retry, timeout, and validation.

Examples: RequestLoggingAsync, UseResiliencePipeline, UseInboxAsync

See: Building a Pipeline

Request Validation

Pipeline middleware that validates a Request's data before the business handler runs. Opt in per handler with the [ValidateRequest] (or [ValidateRequestAsync]) attribute, and choose a validation provider — FluentValidation, DataAnnotations, or Brighter's Specification pattern — by registering one of the provider packages. An invalid request throws a RequestValidationException and the handler never runs.

Not to be confused with pipeline validation, which checks pipeline configuration at startup (see Pipeline Validation and Diagnostics).

See: Request Validation

Specification

A composable rule object (ISpecification<T> / Specification<T>, in the core Paramore.Brighter package) that pairs a predicate with the ValidationError it reports when unsatisfied. Rules combine with And/Or. Used as one of the Request Validation providers, and for content-based routing in the Agreement Dispatcher.

See: Request Validation

Patterns

Outbox

A pattern for ensuring that messages are sent reliably. The Outbox writes messages to a database in the same transaction as entity changes, guaranteeing that both succeed or fail together. Messages are then dispatched from the Outbox to the message broker.

See: Outbox Pattern, Outbox Support

Inbox

A pattern for deduplication - ensuring that a message is only processed once. The Inbox tracks which messages have been processed and prevents duplicate processing of the same message.

See: Inbox Configuration

Causation Id

The identifier that links an Inbox entry to the Outbox messages produced while handling that request. Every message a handler deposits during one invocation is stamped with the same Causation Id, and so is the Inbox entry recording that the request was handled — which is what lets a later duplicate find its own downstream messages. It defaults to the handled request's own Id. Distinct from the Correlation Id, which ties a reply back to its request; neither is derived from the other.

See: Causation Id

Replay (Inbox)

The OnceOnlyAction that makes duplicate detection re-dispatch the Outbox messages produced during the original handling, instead of throwing or logging a warning. The handler does not run again: Brighter looks up the Inbox entry's Causation Id, clears the dispatched state of the Outbox messages stored under it, and the Sweeper sends them on its next pass. Used to walk a stalled workflow forward when an upstream step succeeded but its downstream message was lost.

See: Replay On Seen

Sweeper

A background process that monitors an Outbox and dispatches messages that have not yet been sent. The Sweeper provides guaranteed, at-least-once delivery by continuously attempting to send messages until they succeed.

See: Outbox Support

Archiver

A background process that moves messages older than a configured age out of the Outbox into long-term storage, keeping the Outbox small. Like the Sweeper, it runs as a singleton, coordinated by a Distributed Lock on the resource named "Archiver".

See: Outbox Archiver

Claim Check

A pattern for handling large messages. Instead of sending the entire message through the broker, the large payload is stored externally (e.g., in S3 or blob storage), and only a reference (claim check) is sent in the message. The receiver retrieves the payload using the claim check.

See: Default Message Mappers, S3 Luggage Store

Request-Reply

A pattern in which a request for work has a matching response. Because Brighter and Darker enforce Command-Query Separation between them, a request that changes state is a Command with an Event describing the change, while a request for state is a Query returning a Result. A common shape is to change state through Brighter and read the result of that change back through Darker.

See: Returning Results from a Handler

Database Provisioning

BoxProvisioning

The Brighter library family that creates and migrates relational Outbox and Inbox tables at application startup. Shipped as Paramore.Brighter.BoxProvisioning (core) plus one per backend (*.MsSql, *.PostgreSql, *.MySql, *.Sqlite, *.Spanner). Registered via services.AddBrighter().UseBoxProvisioning(...).

See: Box Provisioning, Configuring Box Provisioning

Migration Chain

The ordered list of BoxMigration records (V1..V_latest) that, when applied in sequence, evolve a Brighter Outbox or Inbox table from its earliest shipped shape to the current schema. The chain is per-backend and per-box-type. Outbox: V1..V7 on all four relational backends. Inbox: V1..V2 on MSSQL/MySQL/SQLite; V1 only on PostgreSQL.

See: Box Provisioning

Migration History Table

The table BoxProvisioning creates and maintains to track which migrations have been applied. Named __BrighterMigrationHistory on every backend except Spanner (where it is BrighterMigrationHistory — no leading underscores, per Spanner naming rules). Primary key (SchemaName, BoxTableName, MigrationVersion). Visible to operators and DBAs.

See: Box Provisioning

Bootstrap Path

One of BoxProvisioning's three runner paths. Triggered when the Outbox or Inbox table exists but the migration history table has no rows for it — typically a pre-existing deployment adopting BoxProvisioning for the first time. The runner introspects columns to detect which schema version the table is at, writes a synthetic history row, then applies any subsequent migrations. Contrast with fresh install (no table) and normal migration (table + history).

See: Upgrading Existing Deployments

Advisory Lock

A database-native lock primitive that BoxProvisioning uses to serialise migration runs across multiple instances of the same application starting simultaneously. Per-backend: sp_getapplock (MSSQL), pg_try_advisory_lock (PostgreSQL), GET_LOCK (MySQL), BEGIN IMMEDIATE (SQLite — file-level lock, not strictly an advisory lock). Held for the duration of one migration run; released on commit or rollback. Configurable via MigrationLockTimeout (default: 30 seconds).

See: Configuring Box Provisioning

Distributed Lock

A lock held in shared infrastructure (a database, blob store, and so on) that lets multiple application instances coordinate so only one performs a task at a time. Brighter uses it to keep a single Outbox Sweeper and Archiver active when you scale out, through the IDistributedLock abstraction and a provider for each backend (DynamoDB, Postgres, MS SQL, MySQL, Azure Blob, MongoDB, Firestore). Related to, but broader than, the Advisory Lock used by BoxProvisioning.

See: Distributed Lock

Messaging Terms

Producer

A component that sends messages to external middleware. Configured using publications.

See: Configuring Producers

Subscription

Configuration for a Consumer that defines how to receive messages from a specific topic or queue. Includes message pump configuration, routing keys, and other transport-specific settings.

See: RabbitMQ Configuration, Kafka Configuration

Publication

Configuration for a Producer that defines how to send messages to a specific topic or queue. Maps message types to routing keys and topics.

See: Basic Configuration

Message Mapper

A component that converts between Requests (C# objects) and Messages (wire format). Message Mappers handle serialization, deserialization, and header mapping.

Interface: IAmAMessageMapper<T>

Note: In V10, explicit message mappers are often not needed - default JSON mappers are used automatically.

See: Message Mappers, Default Message Mappers

Transform

A message transformation applied in a pipeline. Transforms can compress, encrypt, or apply other transformations to messages. Used with attributes like [ClaimCheck], [Compression], [Encryption].

See: Default Message Mappers

Message

The wire format representation of a Request. Contains headers (metadata) and body (payload). Messages are transported over middleware like RabbitMQ, Kafka, or AWS SQS.

Class: Message

See: Message Mappers

Message Oriented Middleware (MoM)

The class of software that delivers a Message from one process to another. Brighter reaches it through a Transport, and supports only broker-based middleware rather than point-to-point; for point-to-point semantics, configure a routing table entry that delivers to a single queue or stream.

See: The Task Queue Pattern

At-Least-Once

The delivery guarantee messaging makes: a message arrives one or more times, never zero times. It follows from a sender being unable to tell a lost message from a lost acknowledgement — so it retries. The Outbox and its Sweeper retry until the broker confirms; a stream transport retries by re-reading the offsets it never committed. Duplicates are therefore normal rather than exceptional: make handlers idempotent, or keep an Inbox so a message you have already seen is discarded.

See: Guaranteed, At Least Once

Message Queue

Middleware that delivers Messages via a queue. A consumer locks a message, processes it and acknowledges it, at which point it is deleted; other consumers read past a locked message, which is what makes competing consumers possible. A nack releases the lock and makes the message visible again, sometimes after a delay.

Examples: SQS, AMQP 0-9-1 (RabbitMQ), AMQP 1.0 (Azure Service Bus)

See: RabbitMQ Configuration

Event Stream

Middleware that delivers Messages via a stream. A consumer reads from an offset and stores its own position, so it can resume where it left off or reset and re-read; it neither locks nor deletes what it reads. Partitioning a stream lets consumers scale.

Examples: Kafka, Kinesis, Redis Streams

See: Kafka Configuration

Partition

One of the ordered logs a stream is divided into. Order is guaranteed within a partition and nowhere else, and only one consumer in a consumer group reads a given partition at a time — which is what lets a stream scale past a single reader without losing order. A Partition Key is the value that chooses the partition; the partition is the log it chooses. Messages sharing a key therefore share a partition, and so keep their order relative to one another.

See: Kafka Configuration

Consumer Group

The consumers that share a group id and so share the work of reading a topic. Kafka assigns each partition to exactly one member, so a group scales up to the partition count and no further, and a rebalance moves partitions between members when the pool changes. Each group tracks its own offsets, which is why two groups read the same topic independently. Brighter does not default the group id — a Kafka Subscription must set it.

See: Kafka Configuration

Offset

A consumer's position in a partition. Brighter turns the Confluent client's auto-store and auto-commit off and manages offsets itself: it stores one when a request is acked, and commits them in batches of CommitBatchSize10 by default — or when the sweep interval elapses, whichever comes first. So a crash loses whatever is still buffered and the consumer group is served those records again. That is where a stream transport's at-least-once delivery comes from, and why a handler reading a stream must be prepared to see a message twice.

See: Kafka Configuration

Dead Letter Queue (DLQ)

A queue holding messages that could not be processed, kept for investigation rather than discarded. Brighter routes a message there when a handler throws RejectMessageAction, and when the requeue count is exceeded on a subscription that names one. RabbitMQ and Azure Service Bus provide a DLQ natively; for other transports Brighter produces the rejected message to a separate channel.

See: Error Handling Options

Nack (Negative Acknowledgment)

Telling the transport that a message was not processed successfully. Throwing DontAckAction from a handler has the message pump apply the transport's own not-acknowledged behaviour: RabbitMQ requeues, SQS resets the visibility timeout, Azure Service Bus releases the lock, and a stream transport such as Kafka simply does not commit the offset. Contrast DeferMessageAction, which schedules a requeue with a delay, and RejectMessageAction, which ends processing.

See: Error Handling

Poison Message

A message that fails every time it is delivered. Left alone it blocks the message pump in a failure-requeue-failure loop, so RequeueCount on the Subscription caps the attempts before the message is rejected.

See: Error Handling

Routing

Routing Key

The destination identifier for a message. In RabbitMQ, this is the routing key. In Kafka, this is the topic. The routing key determines where messages are sent.

See: RabbitMQ Configuration

Topic

A message category or channel. In pub-sub systems, publishers send to topics, and subscribers listen to topics. In Kafka, topics are first-class constructs. In RabbitMQ, topics are implemented using exchanges and routing keys.

See: Kafka Configuration

CloudEvents Type

The message type identifier in the CloudEvents specification. Used for message routing and type resolution in dynamic deserialization scenarios. Format: reverse DNS notation (e.g., io.goparamore.task.created).

See: CloudEvents Support, Dynamic Message Deserialization

DataType Channel

The default routing pattern in Brighter - one message type per channel. Each channel (topic/queue) carries only one type of message, so the channel name determines the message type.

See: Dynamic Message Deserialization

Agreement Dispatcher

A pattern for dynamic handler selection based on request content or context. Instead of a 1-to-1 mapping between request type and handler, Agreement Dispatcher allows runtime selection of which handler(s) should process a request.

Named after Martin Fowler's Agreement Dispatcher pattern.

See: Agreement Dispatcher

Concurrency

Reactor

A concurrency pattern using blocking I/O. The Reactor pattern processes messages synchronously, which provides faster performance per message (no context switch overhead) but may limit throughput under high load.

Configured with: MessagePumpType.Reactor

See: Reactor and Proactor

Proactor

A concurrency pattern using non-blocking I/O. The Proactor pattern processes messages asynchronously with ConfigureAwait(false), which provides better throughput (yields threads during I/O) but adds context switch overhead.

Configured with: MessagePumpType.Proactor

See: Reactor and Proactor

Performer

The message pump - a single-threaded component that pulls messages from middleware and dispatches them to handlers. The Performer can operate in either Reactor or Proactor mode.

Note: In earlier versions, this was called "Message Pump". Current terminology uses "Performer" for the single-threaded pump.

See: Reactor and Proactor

Message Pump

The component that retrieves messages from a transport and dispatches them to handlers. Runs on a single thread (the Performer). Can operate in Reactor mode (blocking) or Proactor mode (non-blocking).

See: How the Dispatcher Works

Resilience

Resilience Pipeline

A Polly v8 pipeline that provides resilience strategies like retry, circuit breaker, timeout, rate limiter, fallback, and hedging. Resilience pipelines replace the legacy UsePolicy attributes in V10.

Configured with: [UseResiliencePipeline] attribute

See: Resilience Pipelines

Circuit Breaker

A resilience pattern that prevents cascading failures. When a certain threshold of failures is reached, the circuit breaker "opens" and stops sending requests to the failing service. After a cooldown period, it enters a "half-open" state to test if the service has recovered.

See: Resilience Pipelines

Retry

A resilience pattern that automatically retries failed operations. Retry policies can use fixed delays, exponential backoff, or jitter to space out retry attempts.

See: Resilience Pipelines

Fallback

A resilience pattern that provides alternative behavior when an operation fails. Fallback can return default values, compensate for failures, queue work for later, or raise alerts.

See: Fallback Policy

Timeout

A resilience pattern that limits how long an operation can run. Timeouts prevent operations from hanging indefinitely and consuming resources.

Note: TimeoutPolicy is deprecated in V10. Use Resilience Pipelines with timeout strategy instead.

See: Resilience Pipelines

Sweeper Circuit Breaking

A pattern for preventing failures when posting to one topic from blocking posting to other topics. The sweeper tracks failures per topic and "trips" a circuit breaker for problematic topics, allowing healthy topics to continue operating.

See: Sweeper Circuit Breaking

CloudEvents and Encodings

CloudEvents

A CNCF specification for describing event data in a common format. CloudEvents provides interoperability between different messaging systems and frameworks.

Specification: CloudEvents v1.0.2

See: CloudEvents Support

Binary-mode CloudEvents

A CloudEvents encoding where attributes are stored in protocol headers and the event data is the message body. Recommended when the protocol supports rich headers (e.g., AMQP, Kafka, RabbitMQ).

See: CloudEvents Support

Structured-mode CloudEvents

A CloudEvents encoding where the entire event (attributes + data) is stored in the message body as JSON. Recommended when the protocol has limited header support (e.g., AWS SNS/SQS).

See: CloudEvents Support

Context

Request Context

An object that carries contextual information through the handler pipeline. Provides access to headers, partition keys, telemetry spans, resilience context, and the originating message.

Interface: IRequestContext

See: Using the Context Bag, Request Context Improvements

Context Bag

A key-value store within the Request Context for passing custom data between handlers in a pipeline. Use well-known keys from RequestContextBagNames for standard values.

See: Using the Context Bag

Originating Message

The original wire-format Message that triggered a handler (available in Consumers). Accessible via Context.OriginatingMessage. Useful for debugging, auditing, and accessing transport-specific metadata.

See: Request Context Improvements

Partition Key

A value used to determine which partition a message should be routed to in partitioned systems like Kafka. Ensures messages with the same key go to the same partition, maintaining order.

See: Request Context Improvements

Scheduler Terms

Scheduler

A component that handles delayed message delivery. Schedulers allow you to send messages at a future time or after a delay.

See: Scheduler Support

InMemory Scheduler

A timer-based scheduler that stores scheduled work in memory. Suitable for development and testing, but not durable - crashes lose scheduled messages.

See: InMemory Scheduler

Quartz Scheduler

A production scheduler using Quartz.NET. Provides persistent, distributed scheduling with clustering support.

See: Quartz Scheduler

Hangfire Scheduler

A production scheduler using Hangfire. Provides persistent scheduling with a web dashboard for monitoring.

See: Hangfire Scheduler

AWS Scheduler

A serverless scheduler using AWS EventBridge Scheduler. Cloud-native option for AWS deployments.

See: AWS Scheduler

Azure Scheduler

A scheduler using Azure Service Bus native scheduling features. Cloud-native option for Azure deployments. Does not support rescheduling - must cancel and create a new schedule.

See: Azure Scheduler

Telemetry

OpenTelemetry (OTel)

An observability framework for collecting traces, metrics, and logs. Brighter V10 uses OpenTelemetry Semantic Conventions for messaging.

See: Telemetry

Activity

The .NET implementation of an OpenTelemetry Span. Represents a unit of work in a distributed trace.

See: Telemetry

Span

A unit of work in a distributed trace. Spans have a start time, duration, and attributes. Spans can be nested to form a trace hierarchy.

See: Telemetry

W3C TraceContext

A W3C standard for propagating trace context between services. Uses traceparent and tracestate headers.

Specification: W3C Trace Context

See: Telemetry

Transports

Transport

The middleware used to send messages between processes. Examples: RabbitMQ, Kafka, AWS SNS/SQS, Azure Service Bus, Redis, MSSQL.

See: Transport-specific configuration pages

InMemory Transport

An in-process transport for development and testing. Messages are stored in memory and delivered within the same process. Not durable - crashes lose messages.

See: InMemory Transport

External Bus

Middleware such as RabbitMQ or Kafka used to send messages between processes. Contrasted with the Internal Bus (in-process).

See: Show me the code!

Internal Bus

In-process message delivery without external middleware. Useful for decoupling components within a single application.

See: Basic Configuration

Other Terms

Nullable Reference Types

DepositPost

A method that writes a message to the Outbox within a database transaction. Used for transactional messaging - guarantees that entity writes and message writes succeed or fail together.

See: Outbox Support

ClearOutbox

A method that dispatches messages from the Outbox to the message broker. Can be called explicitly (low latency) or handled by a Sweeper (automatic retry).

See: Outbox Support

Post

A method that writes a message to the Outbox and immediately attempts to dispatch it. Does not participate in database transactions. Suitable for scenarios where you don't need transactional guarantees.

See: Outbox Support

Dynamic Deserialization

A technique for handling multiple message types on a single channel. Uses a callback (getRequestType) to determine the message type at runtime, typically based on CloudEvents type or message headers.

See: Dynamic Message Deserialization

Industry Standard Terms (EIP)

Brighter and Darker implement many patterns from Enterprise Integration Patterns by Gregor Hohpe and Bobby Woolf:

  • Command Processor = Command pattern + Chain of Responsibility

  • Dispatcher = Message Endpoint + Competing Consumers

  • Outbox = Transactional Outbox pattern

  • Claim Check = Claim Check pattern

  • Message Mapper = Message Translator

  • Pipeline = Pipes and Filters

  • Sweeper = Polling Consumer + Message Store

  • Agreement Dispatcher = Content-Based Router


See Also

Last updated

Was this helpful?