FBus 0.21.5

There is a newer version of this package available.
See the version list below for details.
dotnet add package FBus --version 0.21.5
NuGet\Install-Package FBus -Version 0.21.5
This command is intended to be used within the Package Manager Console in Visual Studio, as it uses the NuGet module's version of Install-Package.
<PackageReference Include="FBus" Version="0.21.5" />
For projects that support PackageReference, copy this XML node into the project file to reference the package.
paket add FBus --version 0.21.5
#r "nuget: FBus, 0.21.5"
#r directive can be used in F# Interactive and Polyglot Notebooks. Copy this into the interactive tool or source code of the script to reference the package.
// 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

Build status

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

Package Status Description
FBus Nuget Core package
FBus.RabbitMQ Nuget RabbitMQ transport
FBus.Json Nuget System.Text.Json serializer
FBus.GenericHost Nuget Generic Host support
FBus.QuickStart Nuget All FBus packages to quick start a project

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 or Reply)

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 FBus
  • make test: build and test FBus

If you prefer to build using your IDE, solution file is named fbus.sln.

Product 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. 
Compatible target framework(s)
Included target framework(s) (in package)
Learn more about Target Frameworks and .NET Standard.

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