# 7.2.0

WARNING

This release changes the JobType table format for job consumers. If you are upgrading, be sure to update your database storage migrations. It may be necessary to truncate the JobType table before starting services after the upgrade to avoid any weird storage errors. See below for more details.

# Durable Futures

This release includes an early access, experimental, brand new, ready to be proven release of Durable Futures. Durable Futures are extensively covered in Season 3 (opens new window) and are ready to be tested in real applications. They are supported, and I expect there will be edge cases to resolve with subsequent releases, but they have been run through many times and tested with multiple saga repositories.

And they're pretty cool if I say so myself!

The ForkJoint (opens new window) sample is a great place to start looking at the code, how it works, and how it should be used. The videos provide all the background and reasoning behind the design. So kick the tires, try them out, and see how they work for you.

# gRPC Transport

MassTransit.Grpc (opens new window)

A new gRPC transport, designed to be a peer-to-peer distributed non-durable message transport, is now included. It's entirely in-memory, has zero dependencies, and allows multiple service instances to exchange messages across a shared message fabric.

Introduction Video (YouTube) (opens new window)

The gRPC is modeled after RabbitMQ, and supports many of the same features. It uses exchanges and queues, and follows the same topology structure as the RabbitMQ transport.

Fanout, Direct, and Topic exchanges are supported, along with routing key support.

And, it, is fast. Using the server GC, message throughput is pretty impressive.

On a single node (essentially in-memory, but serialized via protocol buffers):

Send: 253,774 msg/s
Consume: 172,996 msg/s

Across two nodes, load balanced via competing consumer:

Send: 232,597 msg/s
Consume: 36,331 msg/s

Consume rate is slower because the messages are evenly split across the local and remote node.

Full documentation is coming soon, but for now the host configuration is shown below.

To configure the host using a complete address, such as http://localhost:19796, a Uri can be specified. The following configures a standalone instance, no servers are specified. Incoming connections are of course accepted.

cfg.Host(new Uri("http://localhost:19796"));

To configure a host that connects to other bus instances, use the AddServer method in the host. In this example, the host and port are configured separately. The bus will not start until the server connections are established.

cfg.Host(h =>
{
    h.Host = "127.0.0.1";
    h.Port = 19796;

    h.AddServer(new Uri("127.0.0.1:19797"));
    h.AddServer(new Uri("127.0.0.1:19798"));
});

A complete bus configuration is shown below, using gRPC:

services.AddMassTransit(x =>
{
    x.SetKebabCaseEndpointNameFormatter();

    x.AddConsumer<SubmitClaimConsumer>();

    x.UsingGrpc((context, cfg) =>
    {
        cfg.Host(h =>
        {
            h.Host = "127.0.0.1";
            h.Port = 19796;
        });

        cfg.ConfigureEndpoints(context);
    });
});

Check out the discussion thread (opens new window) for more information.

# Isolated Worker .NET 5 Azure Functions

With .NET 5, the new Azure Function isolated worker support (which actually uses gRPC to communicate between the host and workers) means that the Azure Service Bus and Event Hub SDKs are no longer exposed to functions. This also means that none of the SDK types are available when executing functions. In fact, all you get is byte[] and FunctionContext. Well, that isn't going to stop us from support them and initial (early) support for this model is now available.

The Sample (opens new window) has a v5 branch which uses the new updated support to dispatch messages to consumers, sagas, etc. Since the new isolated worker model is a real service, it's possible to use only the MassTransit.AspNetCore package, which includes the MS DI support along with the hosted service, so you can start MassTransit normally in the function using the worker's IHostedService support. Check out the sample, it's a lot simpler.

But yes, you still need to create your topics, queues, subscriptions, etc. yourself – or use DeployTopologyOnly with a separate console application.

# Resolved Issues

# Conductor

Conductor was first conceptualized back in early 2018 (or sooner) and after three years has failed to turn into anything close to the original design. It turns out, building a distributed, reliable, and scalable service mesh style service discovery service is really, really hard. So it's done, removed, finished, gone, get out of the code. Along with it, the service client, and all the Up/Down/Link/Unlink exchanges created when using it. If you were using it, sorry, I'd suggest just using publish for service discovery – after all, it works and is really all the service client did anyway.

Seriously, it's dead. Buried. The only remaining bits support the job consumers for per-instance job execution (and no, this isn't an advertisement for job consumers).

# BusHealth

The interface IBusHealth and the BusHealth class are now obsolete. The CheckHealth method is now on IBusControl and health state is maintained internally by the bus. It always was, it just wasn't used – this eliminates the redundancy. The supported ASP.NET health checks have already been updated to use the new method, but any previous usage should be changed to IBusControl.

# ConfigureMessageTopology

On a receive endpoint, ConfigureMessageTopology can now be configured per message type, using ConfigureMessageTopology<T>(true | false).

# UseMessageData Storage Configuration

Added new methods to configure the message data repository using a selector, following a similar approach to what is used by saga repositories. For example, to configure Azure Storage as a message data repository:

cfg.UseMessageData(x => x.AzureStorage("storage account connection string"));

# Job Consumers

Several updates (opens new window) were made to job consumer, changing the previous behavior and improving the scalability when running multiple job consumer service instances.

  • Job Consumers are now scaled out per instance, with the concurrency limit applying to each instance. If the concurrency limit specified is 5, and there are three instances, that's 15 jobs running at the same time. Jobs are assigned round robin using the least allocated instance and tracking using the same JobType state machine.
  • Faulted jobs (after retries) will now publish a standard Fault<TJob> event.
  • Completed jobs will now publish a JobCompleted<TJob> event, in addition to the previously published JobCompleted (not job specific) event.
  • Many noisy exchange bindings have been removed, cleaning up the exchanges/topics

TIP

With the removal of Conductor and the service client, the minimal code needed to support the job server instance endpoint remains. It is configured by default to create the instance endpoint, which is used to start jobs on specific instances. There may be some minor tweaks to the configuration required when upgrading.