Skip to content

Releases: hudl/Mjolnir

3.2.1

26 Oct 19:24
c36885a
Compare
Choose a tag to compare

Replace non threaded safe List with a ConcurrentDictionary in bulkhead factory.

A List is not thread-safe. This PR is changing bulkheads subscriptions to a thread-safe concurrent dictionary. That will eliminate race condition while creating bulkheads.

v3.2.0

24 Apr 18:54
94950da
Compare
Choose a tag to compare

This adds the ability to put Bulkheads into a metrics only mode, through configuration at a per bulkhead, with MjolnirConfiguration.BulkheadConfigurations[<bulkhead-key>].MetricsOnly = true, or at global level using MjolnirConfiguration.BulkheadMetricsOnly = true

Bulkhead concurrency is set at 10 by default in Mjolnir, but this really is an arbitrary number and if bulkhead concurrency isn't properly tuned in a production scenario then it's possible to get a lot of BulkheadRejectionExceptions that actually would have been safe to execute without the need to throttle.

The changes in v3.2.0 add the ability to quickly turn off bulkhead rejections during a production scenario like this.

We felt like it was still important to get metrics for rejections during a time when they're effectively not rejecting, as this may help with tuning the concurrency levels in the future - hence "MetricsOnly".

This version also adds a new IMetricEvent implementation, with the GaugeLogMetrics class to help with some of the diagnostic actions mentioned above.

v3.1.1

15 Feb 15:14
6873af3
Compare
Choose a tag to compare

v3.1.0 was released to nuget.org without the proper metadata on the NuGet package. Since nuget.org will no longer let you modify metadata after a package is published and also won't let you delete the package, I'm creating a patched version to fix NuGet metadata.

v3.1.0

15 Feb 13:36
6af36cb
Compare
Choose a tag to compare

Description

This version makes it easier to consume the Mjolnir library on more platforms. From this version will be possible to use it by everything that targets netstandard1.2 or greater.

We've also made properties of the MjolnirConfiguration class virtual and the class is no longer sealed. This will allow easier adaptation of the configuration of Mjolnir.

Changes

Enhancements

  • Add virtual modifiers to MjolnirConfiguration class and remove the sealed keyword from the class.
  • Lower target framework to netstandard1.2
  • Add a new protected constructor to AsyncCommand and SyncCommand to allow for extensions of the classes to override the command name.

Bug fixes

  • Fix bug with not being able to serialize exception due to GroupKey not being serializable

Other

  • Remove global.json content (specific SDK requirement)
  • Include File and assembly version in csproj.

v3.0.0

25 Oct 13:23
Compare
Choose a tag to compare

This release contains breaking changes.

Summary

Major themes:

  • Remove obsolete/deprecated functionality.
  • Focus on CommandInvoker as the library entry point
  • Remove external library dependencies (logging, config, thread pools, common)
  • Make all functionality injectable through ICommandInvoker instead of static assignments
  • .NET Core support

CommandInvoker becomes the sole entry point for the library. See its constructor overloads for DI options. CommandInvoker was introduced in 2.6.0, which is documented here.

Major changes

  • 0e36dd6 Removed old Command. SyncCommand and AsyncCommand, introduced in 2.6.0, are the preferred replacement.
  • 0e36dd6 Removed thread pools and SmartThreadPool dependency. The thread pool behavior (which was used to limit concurrency) uses semaphore-backed bulkheads introduced in 2.6.0. The removal of SmartThreadPool makes converting to .NET Core more manageable (see #16).
  • f83b511 Removed IStats and implementations. The preferred replacement is IMetricEvents.
  • 13320cc Made configuration injectable and removed dependency on Hudl.Config. There is currently no internal replacement for the actual config implementation. Would recommend using ASP.NET Core's Configuration API. See further details on configuration below and in the wiki.
  • 0edaaf2 871ab1c Removed dependency on Hudl.Common. Copied over the few classes (e.g. IClock, UtcSystemClock) that Mjolnir needs.
  • 5dd8295 Make logging injectable and remove dependency on log4net. There is currently no internal replacement for the actual logging implementation.
  • Removed CommandInvoker.Instance, it's an anti-pattern. Prefer to use DI to create and manage a singleton ICommandInvoker throughout your application.
  • e787e52 Moved the circuit breaker "ignored exceptions" (originally set statically on CommandContext) functionality to IBreakerExceptionHandler, which can be injected into CommandInvoker's constructor.
  • Removed ability to configure gauge intervals for metric events. Gauges now fire at a fixed 1000 ms interval; if a client is implementing IMetricEvents and handling gauge calls, the client should handle debouncing or otherwise aggregating the gauges at a less frequent resolution if desired.
  • 88642e9 Internally, CommandContext has been replaced with factory classes; there's no longer a static, central repository for state. Instead, the assumption is that the caller will only create a single CommandInvoker instance (via DI) and reuse it. Callers who need static access should consider creating a static singleton wrapper around a single instance of CommandInvoker. Docs will be updated to make it clear that only a single CommandInvoker should be used throughout an application.
  • 3fb1215 db6ae03 Removed Hudl.Mjolnir.Attributes and the reflective proxying helper classes. Clients can re-implement these if desired, but this 1) removes a dependency on Castle.Core, and 2) though convenient, fosters a pattern (using attributes) that makes code hard to unit test. We may bring this back in the future if it's needed, but if we do it'll be as a separate library instead of built into Mjolnir proper.
  • Convert project format to VS2017 csproj, and reorganize source into src/ and test/unit directories.
  • Mjolnir configuration re-write. It is based on strongly-typed classes now. IMjolnirConfig has been removed.
    To provide configuration into Mjolnir, it is required to instantiate MjolnirConfiguration class and pass it into Mjolnir objects. You should create one instance of this class only. Dependency injection pattern may be used in order to achieve this.
    If reading config from a file is required, an example implementation for JSON file has been provided in test project. See https://github.com/hudl/Mjolnir/pull/63/files#diff-1db9d5dd67e3c39c783fd9759d414387
    In order to update configuration, it is required to call NotifyAfterConfigUpdate on MjolnirConfiguration after any change to MjolnirConfiguration
  • IMjolnirLog interface modification, making it a generic type and adding the Debug(string) method. The IMjolnirLogFactory interface is updated too, making the CreateLog() method typed. The main reason being that it's easier to inject generic types with a DI system and since we we're always creating loggers with typeof(....), it made more sense to make the type generic and reduce the overhead of creating a Type object. See more details below on how to implement these interfaces below.
  • In Mjolnir 3.0.0 we're removing the hard dependency on log4net, and instead using logging interfaces, giving users of the library the chance to wire up the logging to their preferred implementation. The default implementation in the Mjolnir library is a no-op logger (see DefaultMjolnirLog and DefaultMjolnirLogFactory). Since the primary entry point to the Mjolnir library will be the CommandInvoker, you can pass in your own implementation of the IMjolnirLogFactory here.
  • Wiki documentation updated (right now it lives in Version3 branch in wiki project).

Removed / changed public APIs

Removed

  • Hudl.Mjolnir.Attributes CommandAttribute
  • Hudl.Mjolnir.Attributes CommandTimeoutAttribute
  • Hudl.Mjolnir.Attributes FireAndForgetAttribute
  • Hudl.Mjolnir.Command.Attribute CommandAttribute
  • Hudl.Mjolnir.Command.Attribute CommandTimeoutAttribute
  • Hudl.Mjolnir.Command.Attribute FireAndForgetAttribute
  • Hudl.Mjolnir.Command.Attribute CommandInterceptor
  • Hudl.Mjolnir ICommand
  • Hudl.Mjolnir Command<TResult>
  • Hudl.Mjolnir.Command Command
  • Hudl.Mjolnir.Command CommandCancelledException
  • Hudl.Mjolnir.Command CommandFailedException
  • Hudl.Mjolnir.Command CommandRejectedException
  • Hudl.Mjolnir.Command CommandTimeoutException
  • Hudl.Mjolnir.Command CommandContext
  • Hudl.Mjolnir.Command FallbackStatus
  • Hudl.Mjolnir.Command VoidResult
  • Hudl.Mjolnir.External IStats

Changed

  • Hudl.Mjolnir.Key GroupKey no longer has [Serializable] attribute
  • Hudl.Mjolnir.External IMetricEvents.BulkheadConfigGauge() is now BulkheadGauge() and has new parameters for the state of the bulkhead alongside the config values.
  • Hudl.Mjolnir.External IMetricEvents.BreakerConfigGauge() is now BreakerGauge() and has new parameters for the state of the breaker alongside the config values.
  • Breaker and Bulkhead names can no longer be named default - an exception will be thrown if they are. This is to avoid ambiguity with the default config properties.

Removed library dependencies

  • Hudl.Config
  • Hudl.Common
  • SmartThreadPool
  • log4net

Added public APIs

  • Hudl.Mjolnir.External IBreakerExceptionHandler
  • Hudl.Mjolnir.External IMjolnirLogFactory
  • Hudl.Mjolnir.External IMjolnirLog
  • Hudl.Mjolnir.Breaker IgnoredExceptionHandler
  • Hudl.Mjolnir.Config.MjolnirConfiguration MjolnirConfiguration - main class for Mjolnir configuration. Replaces IMjolnirConfig. Holds all configuration values.
  • Hudl.Mjolnir.Config.BreakerConfiguation BreakerConfiguation - configuration values for circuit breakers.
  • Hudl.Mjolnir.Config.BulkheadConfiguration BulkheadConfiguration - configuration values for bulkheads.
  • Hudl.Mjolnir.Config.CommandConfiguration CommandConfiguration - configuration values for commands.

v2.6.0

14 Jun 02:43
Compare
Choose a tag to compare

Pull Requests

  • #45 Upgrade xUnit to 2.0.0
  • #46 Rework API to better work with async and sync calls
  • #50 Upgrade tests to use xUnit 2.0.0 ThrowsAsync assertions

Issues

  • #19 Use counting semaphores instead of thread pools for limiting concurrency
  • #30 Move most README contents to wiki page(s)
  • #42 Configuration prefixes are inconsistent
  • #49 Stack trace information gets lost in fallback re-throw

Notes

All documentation has been moved to the wiki. More detail on the larger changes in this release can be found on #46.

This is a large release, but backwards compatible. SyncCommand and AsyncCommand have been introduced as base classes to replace Command. The original Command still exists, but has been deprecated and will likely be removed in a future major release.

Highlights of the new SyncCommand/AsyncCommand API

  • CommandInvoker with Throw/Return variants - To help force the question of "what should happen on failure", invocation happens via an InvokeThrow or InvokeReturn call, with the latter wrapping any exceptions and letting the caller act more decisively in the face of failure.
  • Improved testability - Testing Command behavior with the original Command API was difficult; the newly-introduced ICommandInvoker can be injected for unit testing.
  • Use semaphore bulkheads (without queues) by default - Thread pools have been replaced by semaphores for lower overhead, dependency reduction, and better async support. There are no longer queues in front of the Bulkhead; re-adding them will be assessed for a future release.
  • Better interface for hooking into metrics - IMetricEvents replaces IStats for a clearer way of hooking into metrics.

Notable differences between new and old Commands

With the two new SyncCommand and AsyncCommand base classes, there are some notable differences in behavior to the original Command base class:

  • The Invoke INFO log is Invoke for both sync and async calls (Invoke Command={0} Breaker={1} Pool={2} Timeout={3}). In the old Command, it's InvokeAsync for the async call.
  • Exceptions aren't wrapped in a CommandFailedException. Instead, the root cause exception is simply rethrown with some Command-specific data attached to it.
  • "Pool" is now "Bulkhead" in a handful of configs, logs, and properties. If porting old Commands over to the new base classes, be sure to duplicate any configured pool values with the appropriate "bulkhead" configuration key.
  • New Commands (sync/async) have a timeout configuration key that starts with mjolnir.command. The old Commands were inconsistent with the rest of the library and just started with command.. Examples:
    • Old: command.my-group.MyCommand.Timeout=1000
    • New: mjolnir.command.my-group.MyCommand.Timeout=1000
  • New commands default to a 2000ms timeout instead of 15000ms.

v2.5.0

23 Oct 18:08
Compare
Choose a tag to compare

#43 - Understand the cause of Mjolnir command failures

Notes:

Prior to this release a CommandFailedException would be thrown with a status of "Canceled", regardless of whether it was an explicit cancellation by a custom CancellationToken or if it was due to Mjolnir's built in timeout CancellationToken. This release changes that status to more accurately reflect the true cause of the cancellation.
This is not considered as a breaking change but may have impact downstream assumptions about the CommandFailedException status codes.

v2.4.0

20 Jul 14:57
Compare
Choose a tag to compare

#41 Ability to disable timeouts for local development.

v2.3.0

23 May 01:49
Compare
Choose a tag to compare

#37 Ability to ignore certain types of exceptions when counting failures for circuit breaker metrics.

v2.2.0

04 Dec 15:48
Compare
Choose a tag to compare
  • #35 Change command loggers to use the command name instead of the generic class name. [Hudl.Mjolnir.Command.Command1]becomes[Hudl.Mjolnir.Command.group-name.CommandName]`.

  • #34 Allow global default configuration via chained ConfigurableValues. Example:

    1. mjolnir.breaker.<breaker-name>.thresholdPercentage
    2. mjolnir.breaker.default.thresholdPercentage
    3. Literal default from CommandContext (50).

    Soft breaking change: Any breakers or pools that had previously been named default will and received specific configuration values will cause those values to get used over the defaults in the code.