Created
March 27, 2020 16:23
-
-
Save mburumaxwell/1eb7f26d4edd32346f5532fe70175566 to your computer and use it in GitHub Desktop.
NGINX for Service Fabric
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
internal sealed class NginxWrapper : StatelessService | |
{ | |
public NginxWrapper(StatelessServiceContext context) : base(context) { } | |
protected override async Task RunAsync(CancellationToken cancellationToken) | |
{ | |
// listen to changes in configuration | |
Context.CodePackageActivationContext.ConfigurationPackageModifiedEvent += OnConfigurationPackageModified; | |
ServiceEventSource.Current.ServiceMessage(Context, "Service started. Configuration changes listener registered"); | |
while (true) | |
{ | |
// if cancellation has been requested, attempt shutdown gracefully but force if it fails | |
if (cancellationToken.IsCancellationRequested) | |
{ | |
ServiceEventSource.Current.ServiceMessage(Context, "Cancellation requested. Graceful shutdown started."); | |
GracefulShutdown(); // attempt graceful shutdown | |
// gracefully shutdown the process within 5 seconds | |
for (var t = 0; t < 5; t++) | |
{ | |
if (!IsRunning) break; // stop looping if it is no longer running | |
await Task.Delay(TimeSpan.FromSeconds(1)); | |
} | |
// if the process is stil running forcefully close | |
if (IsRunning) KillProcesses(); | |
return; // nothing more todo | |
} | |
// ensure the process is still running incase it had been mistakenly dropped | |
if (!IsRunning) | |
{ | |
ServiceEventSource.Current.ServiceMessage( | |
Context, | |
"Either the process was manually stopped or had not be started. Starting the process ..."); | |
SetupAndValidatePaths(); | |
StartProcess(); | |
} | |
// wait a little while before working to prevent over tasking the cpu | |
await Task.Delay(TimeSpan.FromSeconds(5)); | |
} | |
} | |
private string ConfigurationFilePath { get; set; } | |
private string ExecutableFilePath { get; set; } | |
private string RunningProcessName { get; set; } | |
private bool IsRunning => !string.IsNullOrWhiteSpace(RunningProcessName) && Process.GetProcessesByName(RunningProcessName).Any(); | |
private void OnConfigurationPackageModified(object sender, PackageModifiedEventArgs<ConfigurationPackage> e) | |
{ | |
ServiceEventSource.Current.ServiceMessage(Context, "Configuration package was changed. Process shall be restarted"); | |
GracefulShutdown(); | |
KillProcesses(); // kill any pending proceses | |
SetupAndValidatePaths(); | |
StartProcess(); | |
} | |
private void SetupAndValidatePaths() | |
{ | |
var configPackage = Context.CodePackageActivationContext.GetConfigurationPackageObject("Config"); | |
var parameters = configPackage.Settings.Sections["Nginx"].Parameters; | |
var configurationFileName = parameters["ConfigurationFileName"].Value; | |
var executableFileName = parameters["ExecutableFileName"].Value; | |
var codePackageName = Context.CodePackageActivationContext.CodePackageName; | |
ExecutableFilePath = Path.Combine( | |
Context.CodePackageActivationContext.GetCodePackageObject(codePackageName).Path, | |
executableFileName); | |
ConfigurationFilePath = Path.Combine( | |
configPackage.Path, | |
configurationFileName); | |
ServiceEventSource.Current.ServiceMessage( | |
Context, | |
"Setting up service with. {0}={1} and {2}={3}", | |
nameof(ConfigurationFilePath), | |
ConfigurationFilePath, | |
nameof(ExecutableFilePath), | |
ExecutableFilePath); | |
if (!File.Exists(ExecutableFilePath)) | |
throw new FileNotFoundException("The specified executable file must exist", ExecutableFilePath); | |
if (!File.Exists(ConfigurationFilePath)) | |
throw new FileNotFoundException("The specified configuration file must exist", ConfigurationFilePath); | |
} | |
private void KillProcesses() | |
{ | |
if (!string.IsNullOrWhiteSpace(RunningProcessName)) | |
{ | |
var processes = Process.GetProcessesByName(RunningProcessName); | |
ServiceEventSource.Current.ServiceMessage( | |
Context, | |
"Found {0} processes with name {1} to forcefully close.", | |
processes.Length, | |
RunningProcessName); | |
foreach (var p in processes) | |
{ | |
ServiceEventSource.Current.ServiceMessage(Context, "Killing process with Id: {0}", p.Id); | |
p.Kill(); | |
} | |
} | |
} | |
private void StartProcess() => LaunchProcess("-c " + ConfigurationFilePath); | |
private void GracefulShutdown() => LaunchProcess("-c " + ConfigurationFilePath + " -s quit"); | |
private void LaunchProcess(string arguments) | |
{ | |
var process = new Process | |
{ | |
StartInfo = new ProcessStartInfo | |
{ | |
FileName = ExecutableFilePath, | |
WorkingDirectory = Path.GetDirectoryName(ExecutableFilePath), | |
UseShellExecute = false, | |
Arguments = arguments, | |
}, | |
}; | |
ServiceEventSource.Current.ServiceMessage( | |
Context, | |
"Starting process {0} at {1} with arguments {2}", | |
Path.GetFileName(process.StartInfo.FileName), | |
process.StartInfo.FileName, | |
process.StartInfo.Arguments); | |
process.Start(); | |
RunningProcessName = process.ProcessName; | |
ServiceEventSource.Current.ServiceMessage(Context, "Service started with name: {0}", RunningProcessName); | |
} | |
} |
Sign up for free
to join this conversation on GitHub.
Already have an account?
Sign in to comment