Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

if not specified in HOCON, set AppVersion to executing assembly version #4618

Merged
merged 6 commits into from Dec 16, 2020
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Jump to
Jump to file
Failed to load files.
Diff view
Diff view
16 changes: 15 additions & 1 deletion src/core/Akka.Cluster.Tests/ClusterConfigSpec.cs
Expand Up @@ -8,6 +8,7 @@
using System;
using System.Collections.Immutable;
using Akka.Actor;
using Akka.Configuration;
using Akka.Dispatch;
using Akka.Remote;
using Akka.TestKit;
Expand Down Expand Up @@ -46,7 +47,9 @@ public void Clustering_must_be_able_to_parse_generic_cluster_config_elements()
settings.MinNrOfMembers.Should().Be(1);
settings.MinNrOfMembersOfRole.Should().Equal(ImmutableDictionary<string, int>.Empty);
settings.Roles.Should().BeEquivalentTo(ImmutableHashSet<string>.Empty);
settings.AppVersion.Should().Be(AppVersion.Zero);

var appVersion = AppVersion.AppVersionFromAssemblyVersion();
settings.AppVersion.Should().Be(appVersion);
settings.UseDispatcher.Should().Be(Dispatchers.InternalDispatcherId);
settings.GossipDifferentViewProbability.Should().Be(0.8);
settings.ReduceGossipDifferentViewProbability.Should().Be(400);
Expand All @@ -67,5 +70,16 @@ public void Clustering_must_be_able_to_parse_generic_cluster_config_elements()
settings.VerboseGossipReceivedLogging.Should().BeFalse();
settings.RunCoordinatedShutdownWhenDown.Should().BeTrue();
}

/// <summary>
/// To verify that overriding AppVersion from HOCON works
/// </summary>
[Fact]
public void Clustering_should_parse_nondefault_AppVersion()
{
Config config = "akka.cluster.app-version = \"0.0.0\"";
var settings = new ClusterSettings(config.WithFallback(Sys.Settings.Config), Sys.Name);
settings.AppVersion.Should().Be(AppVersion.Zero);
}
}
}
2 changes: 2 additions & 0 deletions src/core/Akka.Cluster/ClusterSettings.cs
Expand Up @@ -9,6 +9,7 @@
using System.Collections.Generic;
using System.Collections.Immutable;
using System.Linq;
using System.Reflection;
using Akka.Actor;
using Akka.Configuration;
using Akka.Dispatch;
Expand Down Expand Up @@ -69,6 +70,7 @@ public ClusterSettings(Config config, string systemName)

Roles = clusterConfig.GetStringList("roles", new string[] { }).ToImmutableHashSet();
AppVersion = Util.AppVersion.Create(clusterConfig.GetString("app-version"));

MinNrOfMembers = clusterConfig.GetInt("min-nr-of-members", 0);

_useDispatcher = clusterConfig.GetString("use-dispatcher", null);
Expand Down
11 changes: 10 additions & 1 deletion src/core/Akka.Cluster/Configuration/Cluster.conf
Expand Up @@ -92,7 +92,16 @@ akka {
# It has support for https://github.com/dwijnand/sbt-dynver format with `+` or
# `-` separator. The number of commits from the tag is handled as a numeric part.
# For example `1.0.0+3-73475dce26` is less than `1.0.10+10-ed316bd024` (3 < 10).
app-version = "0.0.0"
#
# DEFAULT: by default the app-version will default to the entry assembly's version,
# i.e. the assembly of the executable running `Program.cs`
#
# Values can be "assembly-version" or a version string as defined above, i.e.
# app-version = "1.0.0"
# app-version = "1.1-beta1"
# app-version = "1"
# app-version = "1.1"
app-version = assembly-version
Copy link
Member Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Changed the default value here to assembly-version, which activates this assembly-scanning default behavior


# Run the coordinated shutdown from phase 'cluster-shutdown' when the cluster
# is shutdown for other reasons than when leaving, e.g. when downing. This
Expand Down
70 changes: 51 additions & 19 deletions src/core/Akka/Util/AppVersion.cs
Expand Up @@ -8,7 +8,9 @@
using System;
using System.Collections.Generic;
using System.Linq;
using System.Reflection;
using System.Runtime.CompilerServices;
using Akka.Configuration;
using Newtonsoft.Json;

namespace Akka.Util
Expand All @@ -32,20 +34,50 @@ namespace Akka.Util
public class AppVersion : IComparable<AppVersion>, IEquatable<AppVersion>
{
public static readonly AppVersion Zero = new AppVersion("0.0.0");

// made internal for testing purposes
internal const string AssemblyVersionMarker = "assembly-version";
private const int Undefined = 0;

private int[] numbers = Array.Empty<int>();
private string rest = "";
private int[] _numbers = Array.Empty<int>();
private string _rest = "";

[JsonConstructor]
internal AppVersion(string version)
{
this.Version = version;
Version = version;
}

public static AppVersion Create(string version)
{
var v = new AppVersion(version);
// check to see if we're going to use the assembly-version
if (version.Equals(AssemblyVersionMarker, StringComparison.InvariantCultureIgnoreCase))
Copy link
Member Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Check to see if we're using assembly-version - if so, get the assembly data. If not, parse the version string as usual.

{
return AppVersionFromAssemblyVersion();
}

var v2 = new AppVersion(version);
return v2.Parse();
}

/// <summary>
/// INTERNAL API
/// </summary>
/// <remarks>
/// Internal for testing purposes only.
/// </remarks>
internal static AppVersion AppVersionFromAssemblyVersion()
{
// user hasn't specified AppVersion in HOCON
// try looking it up via assembly
var entryAssembly = Assembly.GetEntryAssembly();

// if the entryAssembly is null (which can happen when we're called from unmanaged code)
// then fall back to the executing assembly for the version number.
var targetAssembly = entryAssembly ?? Assembly.GetExecutingAssembly();
Copy link
Member Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Grab the EntryAssembly preferably. If this value is null, which can happen when called from unmanaged code (this happens when the XUnit test runner is executing from within visual studio, for instance) then fallback to the ExecutingAssembly version. Shouldn't happen in most Akka.NET applications, which tend to be launched as 100% managed processes.


var name = targetAssembly.GetName();
var v = new AppVersion($"{name.Version.Major}.{name.Version.Minor}.{name.Version.Build}");
return v.Parse();
}

Expand Down Expand Up @@ -110,7 +142,7 @@ private AppVersion Parse()
}
}

if (numbers.Length == 0)
if (_numbers.Length == 0)
{
var nbrs = new int[4];
var segments = Version.Split('.');
Expand Down Expand Up @@ -168,8 +200,8 @@ private AppVersion Parse()
throw new ArgumentOutOfRangeException($"Only 3 digits separated with '.' are supported. [{Version}]");
}

this.rest = rst;
this.numbers = nbrs;
this._rest = rst;
this._numbers = nbrs;
}
return this;
}
Expand All @@ -183,24 +215,24 @@ public int CompareTo(AppVersion other)
Parse();
other.Parse();
var diff = 0;
diff = numbers[0] - other.numbers[0];
diff = _numbers[0] - other._numbers[0];
if (diff == 0)
{
diff = numbers[1] - other.numbers[1];
diff = _numbers[1] - other._numbers[1];
if (diff == 0)
{
diff = numbers[2] - other.numbers[2];
diff = _numbers[2] - other._numbers[2];
if (diff == 0)
{
diff = numbers[3] - other.numbers[3];
diff = _numbers[3] - other._numbers[3];
if (diff == 0)
{
if (rest == "" && other.rest != "")
if (_rest == "" && other._rest != "")
diff = 1;
if (other.rest == "" && rest != "")
if (other._rest == "" && _rest != "")
diff = -1;
else
diff = rest.CompareTo(other.rest);
diff = _rest.CompareTo(other._rest);
}
}
}
Expand Down Expand Up @@ -235,11 +267,11 @@ public override int GetHashCode()
{
Parse();
var hashCode = 13;
hashCode = (hashCode * 397) ^ numbers[0];
hashCode = (hashCode * 397) ^ numbers[1];
hashCode = (hashCode * 397) ^ numbers[2];
hashCode = (hashCode * 397) ^ numbers[3];
hashCode = (hashCode * 397) ^ rest.GetHashCode();
hashCode = (hashCode * 397) ^ _numbers[0];
hashCode = (hashCode * 397) ^ _numbers[1];
hashCode = (hashCode * 397) ^ _numbers[2];
hashCode = (hashCode * 397) ^ _numbers[3];
hashCode = (hashCode * 397) ^ _rest.GetHashCode();
return hashCode;
}

Expand Down