Skip to content

Commit 520d1ff

Browse files
committed
added Lighthouse code
1 parent b9fdab4 commit 520d1ff

File tree

9 files changed

+308
-0
lines changed

9 files changed

+308
-0
lines changed
Lines changed: 14 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,14 @@
1+
<Project Sdk="Microsoft.NET.Sdk">
2+
<Import Project="..\common.props" />
3+
<PropertyGroup>
4+
<TargetFramework>net452</TargetFramework>
5+
</PropertyGroup>
6+
<ItemGroup>
7+
<PackageReference Include="Microsoft.NET.Test.Sdk" Version="15.0.0" />
8+
<DotNetCliToolReference Include="dotnet-xunit" Version="$(XunitVersion)" />
9+
<PackageReference Include="xunit" Version="2.3.1" />
10+
</ItemGroup>
11+
<ItemGroup>
12+
<ProjectReference Include="..\Lighthouse\Lighthouse.csproj" />
13+
</ItemGroup>
14+
</Project>

src/Lighthouse/Lighthouse.csproj

Lines changed: 21 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,21 @@
1+
<Project Sdk="Microsoft.NET.Sdk">
2+
<PropertyGroup>
3+
<OutputType>Exe</OutputType>
4+
<TargetFrameworks>netcoreapp1.1;net452</TargetFrameworks>
5+
</PropertyGroup>
6+
<ItemGroup>
7+
<PackageReference Include="Akka.Cluster" Version="1.3.7" />
8+
<PackageReference Include="Microsoft.Extensions.Configuration" Version="1.1.2" />
9+
<PackageReference Include="Microsoft.Extensions.Configuration.Xml" Version="1.1.2" />
10+
<PackageReference Include="Petabridge.Cmd.Cluster" Version="0.3.3" />
11+
</ItemGroup>
12+
<!-- Conditionally obtain references for .NET Framework 4.5.2 -->
13+
<ItemGroup Condition=" '$(TargetFramework)' == 'net452' ">
14+
<PackageReference Include="Topshelf" Version="4.0.3" />
15+
</ItemGroup>
16+
<ItemGroup>
17+
<None Update="akka.hocon">
18+
<CopyToOutputDirectory>PreserveNewest</CopyToOutputDirectory>
19+
</None>
20+
</ItemGroup>
21+
</Project>
Lines changed: 88 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,88 @@
1+
using System;
2+
using System.IO;
3+
using System.Linq;
4+
using Akka.Actor;
5+
using Akka.Configuration;
6+
using ConfigurationException = Akka.Configuration.ConfigurationException;
7+
8+
namespace Lighthouse
9+
{
10+
/// <summary>
11+
/// Launcher for the Lighthouse <see cref="ActorSystem"/>
12+
/// </summary>
13+
public static class LighthouseHostFactory
14+
{
15+
public static ActorSystem LaunchLighthouse(string ipAddress = null, int? specifiedPort = null, string systemName = null)
16+
{
17+
systemName = systemName ?? Environment.GetEnvironmentVariable("ACTORSYSTEM")?.Trim();
18+
ipAddress = ipAddress ?? Environment.GetEnvironmentVariable("CLUSTER_IP")?.Trim();
19+
if (specifiedPort == null)
20+
{
21+
var envPort = Environment.GetEnvironmentVariable("CLUSTER_PORT")?.Trim();
22+
if (!string.IsNullOrEmpty(envPort) && int.TryParse(envPort, out var actualPort))
23+
{
24+
specifiedPort = actualPort;
25+
}
26+
}
27+
28+
var clusterConfig = ConfigurationFactory.ParseString(File.ReadAllText("akka.hocon"));
29+
30+
var lighthouseConfig = clusterConfig.GetConfig("lighthouse");
31+
if (lighthouseConfig != null && string.IsNullOrEmpty(systemName))
32+
{
33+
systemName = lighthouseConfig.GetString("actorsystem", systemName);
34+
}
35+
36+
var remoteConfig = clusterConfig.GetConfig("akka.remote");
37+
38+
if (string.IsNullOrEmpty(ipAddress))
39+
{
40+
ipAddress = remoteConfig.GetString("dot-netty.tcp.public-hostname") ??
41+
"127.0.0.1"; //localhost as a final default
42+
}
43+
44+
int port = specifiedPort ?? remoteConfig.GetInt("dot-netty.tcp.port");
45+
46+
if (port == 0) throw new ConfigurationException("Need to specify an explicit port for Lighthouse. Found an undefined port or a port value of 0 in App.config.");
47+
48+
var selfAddress = $"akka.tcp://{systemName}@{ipAddress}:{port}";
49+
50+
/*
51+
* Sanity check
52+
*/
53+
Console.WriteLine($"[Lighthouse] ActorSystem: {systemName}; IP: {ipAddress}; PORT: {port}");
54+
Console.WriteLine("[Lighthouse] Performing pre-boot sanity check. Should be able to parse address [{0}]", selfAddress);
55+
selfAddress = new Address("akka.tcp", systemName, ipAddress.Trim(), port).ToString();
56+
Console.WriteLine("[Lighthouse] Parse successful.");
57+
58+
var clusterSeeds = Environment.GetEnvironmentVariable("CLUSTER_SEEDS")?.Trim();
59+
60+
var seeds = clusterConfig.GetStringList("akka.cluster.seed-nodes");
61+
if (!string.IsNullOrEmpty(clusterSeeds))
62+
{
63+
var tempSeeds = clusterSeeds.Trim('[', ']').Split(',');
64+
if (tempSeeds.Any())
65+
{
66+
seeds = tempSeeds;
67+
}
68+
}
69+
70+
71+
if (!seeds.Contains(selfAddress))
72+
{
73+
seeds.Add(selfAddress);
74+
}
75+
76+
var injectedClusterConfigString = seeds.Aggregate("akka.cluster.seed-nodes = [", (current, seed) => current + (@"""" + seed + @""", "));
77+
injectedClusterConfigString += "]";
78+
79+
var finalConfig = ConfigurationFactory.ParseString(
80+
string.Format(@"akka.remote.dot-netty.tcp.public-hostname = {0}
81+
akka.remote.dot-netty.tcp.port = {1}", ipAddress, port))
82+
.WithFallback(ConfigurationFactory.ParseString(injectedClusterConfigString))
83+
.WithFallback(clusterConfig);
84+
85+
return ActorSystem.Create(systemName, finalConfig);
86+
}
87+
}
88+
}
Lines changed: 61 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,61 @@
1+
// Copyright 2014-2015 Aaron Stannard, Petabridge LLC
2+
//
3+
// Licensed under the Apache License, Version 2.0 (the "License"); you may not use
4+
// this file except in compliance with the License. You may obtain a copy of the
5+
// License at
6+
//
7+
// http://www.apache.org/licenses/LICENSE-2.0
8+
//
9+
// Unless required by applicable law or agreed to in writing, software distributed
10+
// under the License is distributed on an "AS IS" BASIS, WITHOUT WARRANTIES OR
11+
// CONDITIONS OF ANY KIND, either express or implied. See the License for the
12+
// specific language governing permissions and limitations under the License.
13+
14+
using System;
15+
using System.Threading.Tasks;
16+
using Akka.Actor;
17+
using Akka.Cluster;
18+
using Petabridge.Cmd.Cluster;
19+
using Petabridge.Cmd.Host;
20+
21+
namespace Lighthouse
22+
{
23+
public class LighthouseService
24+
{
25+
private readonly string _ipAddress;
26+
private readonly int? _port;
27+
private readonly string _actorSystemName;
28+
29+
private ActorSystem _lighthouseSystem;
30+
31+
public LighthouseService() : this(null, null, null) { }
32+
33+
public LighthouseService(string ipAddress, int? port, string actorSystemName)
34+
{
35+
_ipAddress = ipAddress;
36+
_port = port;
37+
_actorSystemName = actorSystemName;
38+
}
39+
40+
public void Start()
41+
{
42+
_lighthouseSystem = LighthouseHostFactory.LaunchLighthouse(_ipAddress, _port, _actorSystemName);
43+
var pbm = PetabridgeCmd.Get(_lighthouseSystem);
44+
pbm.RegisterCommandPalette(ClusterCommands.Instance); // enable cluster management commands
45+
pbm.Start();
46+
}
47+
48+
/// <summary>
49+
/// Task completes once the Lighthouse <see cref="ActorSystem"/> has terminated.
50+
/// </summary>
51+
/// <remarks>
52+
/// Doesn't actually invoke termination. Need to call <see cref="StopAsync"/> for that.
53+
/// </remarks>
54+
public Task TerminationHandle => _lighthouseSystem.WhenTerminated;
55+
56+
public async Task StopAsync()
57+
{
58+
await CoordinatedShutdown.Get(_lighthouseSystem).Run();
59+
}
60+
}
61+
}

src/Lighthouse/Program.NetCore.cs

Lines changed: 21 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,21 @@
1+
using System;
2+
3+
namespace Lighthouse
4+
{
5+
public partial class Program
6+
{
7+
#if NETCOREAPP1_1
8+
public static void Main(string[] args)
9+
{
10+
var lighthouseService = new LighthouseService();
11+
lighthouseService.Start();
12+
Console.WriteLine("Press Control + C to terminate.");
13+
Console.CancelKeyPress += async (sender, eventArgs) =>
14+
{
15+
await lighthouseService.StopAsync();
16+
};
17+
lighthouseService.TerminationHandle.Wait();
18+
}
19+
#endif
20+
}
21+
}
Lines changed: 36 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,36 @@
1+
#if NET452
2+
using Topshelf;
3+
#endif
4+
5+
namespace Lighthouse
6+
{
7+
public partial class Program
8+
{
9+
#if NET452
10+
public static void Main(string[] args)
11+
{
12+
HostFactory.Run(x =>
13+
{
14+
x.SetServiceName("Lighthouse");
15+
x.SetDisplayName("Lighthouse");
16+
x.SetDescription("Seed node for the Akka Cluster");
17+
18+
x.UseAssemblyInfoForServiceInfo();
19+
x.RunAsLocalSystem();
20+
x.StartAutomatically();
21+
22+
x.Service<LighthouseService>(sc =>
23+
{
24+
sc.ConstructUsing(() => new LighthouseService());
25+
26+
// the start and stop methods for the service
27+
sc.WhenStarted(s => s.Start());
28+
sc.WhenStopped(s => s.StopAsync().Wait());
29+
});
30+
31+
x.EnableServiceRecovery(r => r.RestartService(1));
32+
});
33+
}
34+
#endif
35+
}
36+
}

src/Lighthouse/akka.hocon

Lines changed: 38 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,38 @@
1+
lighthouse{
2+
actorsystem: "actor-system" #POPULATE NAME OF YOUR ACTOR SYSTEM HERE
3+
}
4+
5+
# See petabridge.cmd configuration options here: https://cmd.petabridge.com/articles/install/host-configuration.html
6+
petabridge.cmd{
7+
# default IP address used to listen for incoming petabridge.cmd client connections
8+
# should be a safe default as it listens on "all network interfaces".
9+
host = "0.0.0.0"
10+
11+
# default port number used to listen for incoming petabridge.cmd client connections
12+
port = 9110
13+
}
14+
15+
akka {
16+
actor {
17+
provider = cluster
18+
}
19+
20+
remote {
21+
log-remote-lifecycle-events = DEBUG
22+
dot-netty.tcp {
23+
transport-class = "Akka.Remote.Transport.DotNetty.TcpTransport, Akka.Remote"
24+
applied-adapters = []
25+
transport-protocol = tcp
26+
#will be populated with a dynamic host-name at runtime if left uncommented
27+
#public-hostname = "POPULATE STATIC IP HERE"
28+
hostname = "0.0.0.0"
29+
port = 4053
30+
}
31+
}
32+
33+
cluster {
34+
#will inject this node as a self-seed node at run-time
35+
seed-nodes = []
36+
roles = [lighthouse]
37+
}
38+
}

src/Lighthouse/get-dockerip.sh

Lines changed: 11 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,11 @@
1+
#!/bin/sh
2+
3+
if [ -z "$CLUSTER_IP" ]; then
4+
host=$(hostname -i)
5+
echo "Docker container bound on $host"
6+
export CLUSTER_IP="$host"
7+
else
8+
echo "Docker container bound on $CLUSTER_IP"
9+
fi
10+
11+
exec "$@"

src/common.props

Lines changed: 18 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,18 @@
1+
<Project>
2+
<PropertyGroup>
3+
<Copyright>Copyright © 2015-2018 Petabridge, LLC</Copyright>
4+
<Authors>Petabridge</Authors>
5+
<VersionPrefix>0.9.2</VersionPrefix>
6+
<PackageReleaseNotes>Upgraded to Akka.NET 1.3.7.</PackageReleaseNotes>
7+
<PackageIconUrl>
8+
</PackageIconUrl>
9+
<PackageProjectUrl>
10+
</PackageProjectUrl>
11+
<PackageLicenseUrl>
12+
</PackageLicenseUrl>
13+
<NoWarn>$(NoWarn);CS1591</NoWarn>
14+
</PropertyGroup>
15+
<PropertyGroup>
16+
<XunitVersion>2.3.0-beta4-*</XunitVersion>
17+
</PropertyGroup>
18+
</Project>

0 commit comments

Comments
 (0)