FBus 0.21.5
See the version list below for details.
dotnet add package FBus --version 0.21.5
NuGet\Install-Package FBus -Version 0.21.5
<PackageReference Include="FBus" Version="0.21.5" />
paket add FBus --version 0.21.5
#r "nuget: FBus, 0.21.5"
// Install FBus as a Cake Addin
#addin nuget:?package=FBus&version=0.21.5
// Install FBus as a Cake Tool
#tool nuget:?package=FBus&version=0.21.5
FBus
FBus is a lightweight service-bus implementation written in F#.
It comes with default implementation for:
- Publish (broadcast), Send (direct) and Reply (direct)
- Conversation follow-up using headers (ConversationId and MessageId)
- RabbitMQ (with dead-letter support)
- Generic Host support with dependency injection
- System.Text.Json serialization
- Full testing capabilities using In-Memory mode
- Persistent queue/buffering across activation
Following features might appear in future revisions:
- Parallelism support via sharding
Features that won't be implemented in FBus:
- Sagas: coordination is a big topic by itself - technically, everything required to handle this is available (ConversationId and MessageId). This can be handled outside of a service-bus.
Available packages
Api
Messages
In order to exchange messages using FBus, you have first to define messages. There are 2 types:
- events: messages that are broadcasted (see
Publish
) - commands: messages that are sent to one client (see
Send
orReply
)
In order to avoid mistakes, messages are marked with a dummy interface:
For events:
type EventMessage =
{ msg: string }
interface FBus.IMessageEvent
For commands:
type CommandMessage =
{ msg: string }
interface FBus.IMessageCommand
For more information, see CQRS/Event Sourcing literature.
Builder
Prior using the bus, a configuration must be built:
FBus.Builder | Description | Default |
---|---|---|
configure |
Start configuration with default parameters. | |
withName |
Change service name. Used to identify a bus client (see IBusInitiator.Send and IBusConversation.Send ) |
Name based on computer name, pid and random number. |
withTransport |
Transport to use. | None |
withContainer |
Container to use | None |
withSerializer |
Serializer to use | None |
withConsumer |
Add message consumer | None |
withHook |
Hook on consumer message processing | None |
withRecovery |
Connect to dead letter for recovery only | false |
build |
Returns a new bus instance (FBus.IBusControl ) based on configuration |
n/a |
Note: bus clients are ephemeral by default - this is useful if you just want to connect to the bus for spying or sending commands for eg 😃 Assigning a name (see withName
) makes the client public so no queues are deleted upon exit.
Bus
IBusControl
is the primary interface to control the bus:
IBusControl | Description | Comments |
---|---|---|
Start |
Start the bus. Returns IBusInitiator |
Must be called before sending messages. Start accepts a resolve context which can be used by the container. |
Stop |
Stop the bus. | Bus can be restarted later on. |
Dispose |
Dispose the bus instance. | Bus can't be reused. |
Once bus is started, IBusInitiator
is available:
IBusInitiator | Description |
---|---|
Publish |
Broadcast an event message to all subscribers. |
Send |
Send a command message to given client. |
Note: a new conversation is started when using this interface.
Consumer
A consumer processes incoming messages: a context is provided (IBusConversation
) and a message.
IBusConversation
provides information to handlers and means to interact with the bus:
IBusConversation | Description |
---|---|
Sender |
Name of the client. |
ConversationId |
Id of the conversation (identifier is flowing from initiator to subsequent consumers). |
MessageId |
Id the this message. |
Reply |
Provide a shortcut to reply to sender. |
Publish |
Broadcast an event message to all subscribers. |
Send |
Send a command message to given client. |
Note: the current conversation is used when using this interface.
There are two kind of handlers:
Class
Implement IBusConsumer
interface on the class. Multiple implementation are allowed as of F# 5.0.
Use withConsumer
to register the handlers.
type IBusConsumer<'t> =
abstract Handle: IBusConversation -> 't -> unit
Function
A function which enable partial application scenario: use withFunConsumer
.
Use withFunConsumer
to register the handler.
InMemory
FBus provides InMemory implementation for transport, serializer and activator. They only exist to help testing or to easily prototype.
FBus.InMemory | Description | Comments |
---|---|---|
useTransport |
Register InMemory transport | |
useSerializer |
Register marshal by reference serializer | Object is preserved and passed by reference. |
useContainer |
Register default activator (see System.Activator ) |
Default constructor must exist. |
NOTE: InMemory serializer does leak messages. This is by design.
Testing
FBus can work in-memory, this is especially useful when unit-testing. Prior running a test in-memory, an FBus.Testing.Session
instance has to be created. Multiple sessions can be created, they are completely isolated.
FBus.Testing.Session | Description | Comments |
---|---|---|
Use |
Configure FBus for unit-testing | Configure transport, serializer and activator. |
WaitForCompletion |
Wait for all messages to be processed | This method blocks until completion. |
ClearCache |
Clear InMemory serializer cache | Shall not be used unless necessary. |
Extensibility
Following extension points are supported:
- Transports: which middleware is transporting messages.
- Serializers: how messages are exchanged on the wire.
- Containers: where and how consumers are allocated and hosted.
- Hooks: handlers in case of failures.
Messages
There are 2 types of messages:
- events: messages that are broadcasted (see
Publish
) - commands: messages that are sent to one client (understand
Send
)
In order to avoid mistakes, messages are marked with a dummy interface.
For events:
type EventMessage =
{ msg: string }
interface FBus.IMessageEvent
For commands:
type CommandMessage =
{ msg: string }
interface FBus.IMessageCommand
Transports
Two transports are available out of the box: RabbitMQ and InMemory. Still, it's possible to easily add new middlewares.
See FBus.IBusTransport
.
Containers
Containers are in charge of activating and running consumers.
See FBus.IBusContainer
.
Serializers
Serializers transform objects into byte streams and vis-versa without relying on native middleware capabilities.
See FBus.IBusSerializer
.
Consumers
Consumers can be configured at will. There is one major restriction: only one handler per type is supported. If you want several subscribers, you will have to handle delegation.
See FBus.IBusConsumer<>
.
Hooks
Allow one to observe errors while processing messages.
See FBus.IBusHook
.
FBus.IBusHook | Description | Comments |
---|---|---|
OnStart |
Invoked after the bus is started - use to start additional services if required | |
OnStop |
Invoked before the bus is stopped - use to stop additional services if required | |
OnBeforeProcessing |
Invoked before processing a message | Must not throw - can return an IDisposable object released once processing is done. |
OnError |
Invoked on error | Must not throw. |
Available extensions
RabbitMQ (package FBus.RabbitMQ)
FBus.RabbitMQ | Description | Comments |
---|---|---|
useDefaults |
Configure RabbitMQ as transport | Endpoint is set to amqp://guest:guest@localhost . |
useWith |
Configure RabbitMQ as transport with provided URI |
Transport leverages exchanges (one for each message type) to distribute messages across consumers (subscribing a queue).
Json (package FBus.Json)
FBus.Json | Description | Comments |
---|---|---|
useDefaults |
Configure System.Text.Json as serializer | FSharp.SystemTextJson](https://github.com/Tarmil/FSharp.SystemTextJson) is used to deal with F# types. |
useWith |
Same as useDefaults but with provided configuration options |
QuickStart (package FBus.QuickStart)
FBus.QuickStart | Description | Comments
configure
| Configure FBus with RabbitMQ, Json and In-Memory Activator. |
GenericHost
FBus.GenericHost | Description | Comments |
---|---|---|
AddFBus |
Inject FBus in GenericHost container | FBus.IBusControl and FBus.IBusInitiator are available in injection context. |
Thread safety
FBus is thread-safe. Plugin implementation shall be thread-safe as well.
RabbitMQ transport
FBus.RabbitMQ
package implements a RabbitMQ transport. It supports only a simple concurrency model:
- no concurrency at bus level for receive. This does not mean you can't have concurrency, you just have to handle it explicitely: you have to create multiple bus instances in-process and it's up to you to synchronize correctly among threads if required.
- Sending is a thread safe operation - but locking happens behind the scene to access underlying channel/connection.
- Automatic recovery is configured on connection.
The default implementation use following settings:
- messages are sent as persistent
- a consumer fetches one message at a time and ack/nack accordingly
- message goes to dead-letter on error
Samples
In-Process console
Client
open FBus
open FBus.Builder
use bus = FBus.QuickStart.configure() |> build
let busInitiator = bus.Start()
busInitiator.Send "hello from FBus !"
Server
open FBus
open FBus.Builder
type MessageConsumer() =
interface IConsumer<Message> with
member this.Handle context msg =
printfn "Received message: %A" msg
use bus = FBus.QuickStart.configure() |> withConsumer<MessageConsumer>
|> build
bus.Start() |> ignore
Server (generic host)
...
let configureBus builder =
builder |> withName "server"
|> withConsumer<MessageConsumer>
|> Json.useDefaults
|> RabbitMQ.useDefaults
Host.CreateDefaultBuilder(argv)
.ConfigureServices(fun services -> services.AddFBus(configureBus) |> ignore)
.UseConsoleLifetime()
.Build()
.Run()
Build it
A makefile is available:
make [build]
: build FBusmake test
: build and test FBus
If you prefer to build using your IDE, solution file is named fbus.sln
.
Product | Versions Compatible and additional computed target framework versions. |
---|---|
.NET | net5.0 was computed. net5.0-windows was computed. net6.0 was computed. net6.0-android was computed. net6.0-ios was computed. net6.0-maccatalyst was computed. net6.0-macos was computed. net6.0-tvos was computed. net6.0-windows was computed. net7.0 was computed. net7.0-android was computed. net7.0-ios was computed. net7.0-maccatalyst was computed. net7.0-macos was computed. net7.0-tvos was computed. net7.0-windows was computed. net8.0 was computed. net8.0-android was computed. net8.0-browser was computed. net8.0-ios was computed. net8.0-maccatalyst was computed. net8.0-macos was computed. net8.0-tvos was computed. net8.0-windows was computed. |
.NET Core | netcoreapp3.0 was computed. netcoreapp3.1 was computed. |
.NET Standard | netstandard2.1 is compatible. |
MonoAndroid | monoandroid was computed. |
MonoMac | monomac was computed. |
MonoTouch | monotouch was computed. |
Tizen | tizen60 was computed. |
Xamarin.iOS | xamarinios was computed. |
Xamarin.Mac | xamarinmac was computed. |
Xamarin.TVOS | xamarintvos was computed. |
Xamarin.WatchOS | xamarinwatchos was computed. |
-
.NETStandard 2.1
- FSharp.Core (>= 5.0.0)
NuGet packages (6)
Showing the top 5 NuGet packages that depend on FBus:
Package | Downloads |
---|---|
FBus.Json
System.Text.Json serializer for FBus. |
|
FBus.RabbitMQ
RabbitMQ transport for FBus. |
|
FBus.GenericHost
GenericHost support for FBus. |
|
FBus.QuickStart
FBus with all dependencies. |
|
FBus.Bridge
Package Description |
GitHub repositories
This package is not used by any popular GitHub repositories.
Version | Downloads | Last updated |
---|---|---|
0.30.0 | 329 | 1/30/2024 |
0.29.0 | 307 | 1/30/2024 |
0.28.0 | 4,359 | 2/13/2023 |
0.27.1 | 3,729 | 8/12/2022 |
0.27.0 | 2,072 | 7/27/2022 |
0.26.0 | 3,529 | 5/14/2022 |
0.25.0 | 1,652 | 9/29/2021 |
0.24.0 | 1,486 | 9/10/2021 |
0.23.0 | 1,408 | 9/8/2021 |
0.22.0 | 1,394 | 9/7/2021 |
0.21.6 | 1,352 | 9/3/2021 |
0.21.5 | 1,333 | 9/3/2021 |
0.21.4 | 1,371 | 9/3/2021 |
0.21.3 | 1,386 | 9/3/2021 |
0.21.2 | 1,366 | 9/3/2021 |
0.21.1 | 1,344 | 9/3/2021 |
0.21.0 | 1,378 | 9/3/2021 |
0.20.1 | 1,261 | 9/3/2021 |
0.20.0 | 1,291 | 9/2/2021 |
0.19.0 | 1,341 | 7/12/2021 |
0.18.0 | 2,199 | 5/15/2021 |
0.17.0 | 1,850 | 5/12/2021 |
0.16.0 | 1,482 | 4/29/2021 |
0.15.0 | 2,324 | 2/12/2021 |
0.14.0 | 1,343 | 2/11/2021 |
0.13.0 | 1,386 | 2/9/2021 |
0.12.0 | 2,489 | 11/23/2020 |
0.11.0 | 1,687 | 11/11/2020 |
0.10.2 | 1,082 | 11/10/2020 |
0.10.1 | 1,042 | 11/10/2020 |
0.10.0 | 1,065 | 11/10/2020 |
0.9.12 | 1,305 | 11/8/2020 |
0.9.11 | 1,288 | 11/8/2020 |
0.9.10 | 1,299 | 11/8/2020 |
0.9.9 | 1,356 | 11/8/2020 |
0.9.8 | 1,256 | 11/8/2020 |
0.9.7 | 1,268 | 11/8/2020 |
0.9.6 | 1,225 | 11/7/2020 |
0.9.5 | 1,233 | 11/7/2020 |
0.9.4 | 839 | 11/7/2020 |
0.9.3 | 877 | 11/7/2020 |
0.9.2 | 875 | 11/7/2020 |
0.9.1 | 866 | 11/7/2020 |
0.9.0 | 903 | 11/7/2020 |
0.8.6 | 1,233 | 11/6/2020 |
0.8.4 | 920 | 11/6/2020 |
0.8.3 | 1,039 | 11/6/2020 |
0.8.0 | 569 | 11/6/2020 |
0.6.9 | 875 | 9/8/2020 |
0.6.8 | 534 | 9/8/2020 |
0.6.7 | 473 | 9/8/2020 |
0.6.6 | 493 | 9/6/2020 |
0.6.5 | 529 | 9/6/2020 |
0.6.4 | 488 | 9/4/2020 |
0.6.3 | 484 | 9/3/2020 |
0.6.2 | 439 | 8/26/2020 |
0.6.1 | 534 | 8/20/2020 |
0.6.0 | 442 | 8/20/2020 |
0.5.7 | 491 | 8/16/2020 |
0.5.6 | 756 | 7/26/2020 |
0.4.2 | 521 | 7/20/2020 |
0.4.1 | 824 | 6/29/2020 |
0.4.0 | 470 | 6/25/2020 |
0.3.3 | 500 | 6/24/2020 |
0.3.2 | 553 | 6/23/2020 |
0.3.1 | 881 | 6/21/2020 |
0.3.0 | 523 | 6/21/2020 |
0.2.2 | 539 | 6/21/2020 |
0.2.1 | 518 | 6/16/2020 |
0.2.0 | 491 | 6/15/2020 |
0.1.3 | 577 | 6/14/2020 |