Skip to content

Commit f512937

Browse files
committed
Split environment variable updating into seperate stages
1 parent 5129dc8 commit f512937

File tree

1 file changed

+68
-35
lines changed

1 file changed

+68
-35
lines changed

tracer/src/Datadog.FleetInstaller/AppHostHelper.cs

Lines changed: 68 additions & 35 deletions
Original file line numberDiff line numberDiff line change
@@ -82,53 +82,48 @@ private static bool ModifyEnvironmentVariablesWithRetry(
8282
// If the IIS host config is being modified, this may fail
8383
// We retry multiple times, as the final update is atomic
8484
// We could consider adding backoff here, but it's not clear that it's necessary
85-
var attempt = 0;
86-
while (attempt < 3)
85+
HashSet<string> appPoolsWeMustReenableRecycling = [];
86+
if (!Retry(log, "disable app pool recycling", () => DisableRecycling(log, out appPoolsWeMustReenableRecycling)))
8787
{
88-
attempt++;
89-
if (attempt > 1)
90-
{
91-
log.WriteInfo($"Attempt {attempt} to update IIS failed, retrying.");
92-
}
93-
94-
if (ModifyEnvironmentVariables(log, envVars, updateEnvVars))
95-
{
96-
return true;
97-
}
88+
// We failed to disable recycling, so we can't do anything more
89+
return false;
9890
}
9991

100-
log.WriteError($"Failed to update IIS after {attempt} attempts");
101-
return false;
102-
}
92+
var success = Retry(log, "update app pool environment variables", () => SetEnvironmentVariables(log, envVars, updateEnvVars));
10393

104-
private static bool ModifyEnvironmentVariables(
105-
ILogger log,
106-
ReadOnlyDictionary<string, string> envVars,
107-
Action<ILogger, ConfigurationElementCollection, ReadOnlyDictionary<string, string>> updateEnvVars)
108-
{
109-
if (!SetEnvironmentVariables(log, envVars, updateEnvVars, out var appPoolsWeMustReenableRecycling))
94+
// We must try to re-enable recycling even if we failed to set the environment variables
95+
return Retry(log, "re-enable app pool recycling", () => ReEnableRecycling(log, appPoolsWeMustReenableRecycling)) && success;
96+
97+
static bool Retry(ILogger log, string actionName, Func<bool> action)
11098
{
111-
// If we failed to set the environment variables, we don't need to re-enable recycling
112-
// because by definition we can't have saved successfully
99+
var attempt = 0;
100+
while (attempt < 3)
101+
{
102+
attempt++;
103+
if (attempt > 1)
104+
{
105+
log.WriteInfo($"Attempt {attempt} to {actionName} failed, retrying.");
106+
}
107+
108+
if (action())
109+
{
110+
return true;
111+
}
112+
}
113+
114+
log.WriteError($"Failed to {actionName} after {attempt} attempts");
113115
return false;
114116
}
115-
116-
// We do this separately, because we have to do all the work again no matter what we do
117-
return ReEnableRecycling(log, appPoolsWeMustReenableRecycling);
118117
}
119118

120119
private static bool SetEnvironmentVariables(
121120
ILogger log,
122121
ReadOnlyDictionary<string, string> envVars,
123-
Action<ILogger, ConfigurationElementCollection, ReadOnlyDictionary<string, string>> updateEnvVars,
124-
out HashSet<string> appPoolsWeMustReenableRecycling)
122+
Action<ILogger, ConfigurationElementCollection, ReadOnlyDictionary<string, string>> updateEnvVars)
125123
{
126-
appPoolsWeMustReenableRecycling = [];
127-
128124
try
129125
{
130126
using var serverManager = new ServerManager();
131-
appPoolsWeMustReenableRecycling = new HashSet<string>(StringComparer.OrdinalIgnoreCase);
132127

133128
var appPoolsSection = GetApplicationPoolsSection(log, serverManager);
134129
if (appPoolsSection is null)
@@ -157,6 +152,46 @@ private static bool SetEnvironmentVariables(
157152
}
158153

159154
log.WriteInfo($"Updating app pool '{poolName}' environment variables");
155+
updateEnvVars(log, appPoolElement.GetCollection("environmentVariables"), envVars);
156+
}
157+
}
158+
159+
log.WriteInfo("Saving applicationHost.config");
160+
serverManager.CommitChanges();
161+
return true;
162+
}
163+
catch (Exception ex)
164+
{
165+
log.WriteError(ex, "Error updating application pools");
166+
return false;
167+
}
168+
}
169+
170+
private static bool DisableRecycling(ILogger log, out HashSet<string> appPoolsWeMustReenableRecycling)
171+
{
172+
try
173+
{
174+
log.WriteInfo("Temporarily disabling app pool recycling");
175+
using var serverManager = new ServerManager();
176+
appPoolsWeMustReenableRecycling = new HashSet<string>(StringComparer.OrdinalIgnoreCase);
177+
178+
var appPoolsSection = GetApplicationPoolsSection(log, serverManager);
179+
if (appPoolsSection is null)
180+
{
181+
return false;
182+
}
183+
184+
foreach (var appPoolElement in appPoolsSection.Value.AppPools)
185+
{
186+
if (string.Equals(appPoolElement.ElementTagName, "add", StringComparison.OrdinalIgnoreCase))
187+
{
188+
// An app pool element
189+
if (appPoolElement.GetAttributeValue("name") is not string poolName)
190+
{
191+
// poolName can never be null, if it is, weirdness is afoot, so bail out
192+
log.WriteInfo("Found app pool element without a name, skipping");
193+
continue;
194+
}
160195

161196
// disable recycling of the pool, so that we don't force a restart when we update the pool
162197
// we can't distinguish between "not set" and "set to false", but we only really care about
@@ -171,9 +206,6 @@ private static bool SetEnvironmentVariables(
171206
appPoolsWeMustReenableRecycling.Add(poolName);
172207
appPoolElement.GetChildElement("recycling")["disallowRotationOnConfigChange"] = true;
173208
}
174-
175-
// Set the pool-specific env variables
176-
updateEnvVars(log, appPoolElement.GetCollection("environmentVariables"), envVars);
177209
}
178210
}
179211

@@ -183,7 +215,8 @@ private static bool SetEnvironmentVariables(
183215
}
184216
catch (Exception ex)
185217
{
186-
log.WriteError(ex, $"Error updating application pools");
218+
appPoolsWeMustReenableRecycling = [];
219+
log.WriteError(ex, "Error updating application pools");
187220
return false;
188221
}
189222
}

0 commit comments

Comments
 (0)