Add monitor to keep track of current value of App Services env vars#870
Add monitor to keep track of current value of App Services env vars#870
Conversation
- Use to keep the value of WEBSITE_SITE_NAME and other App Services values current during runime
| /// </summary> | ||
| internal static class AppServiceEnvVarMonitor | ||
| { | ||
| internal static TimeSpan CheckInterval = TimeSpan.FromSeconds(30); |
There was a problem hiding this comment.
Nit: private static readonly (unless you need to change it in unit tests.)
| /// </summary> | ||
| private static void CheckVariablesIntermittent() | ||
| { | ||
| DateTime checkTime = DateTime.Now; |
There was a problem hiding this comment.
Always use DateTime.UtcNow to avoid an expensive local timezone lookup.
There was a problem hiding this comment.
Done - good tip, thanks.
| private static void CheckVariablesIntermittent() | ||
| { | ||
| DateTime checkTime = DateTime.Now; | ||
| if (checkTime - LastCheckTime > CheckInterval) |
There was a problem hiding this comment.
For bonus perf points, instead of LastCheckTime compute and store NextCheckTime (i.e. the time after which you should check again) and avoid the subtraction in the common case and make it an addition in the rare case.
i.e.
DateTime now = DateTime.UtcNow;
if (now > NextCheckTime)
{
NextCheckTime = now + CheckInterval;
// etc.
}|
@d3r3kk can you please confirm you actually tried it and this code works before I'll be reviewing it? From the fast glance this is NOT the fix that suppose to be working. |
| internal static class AppServiceEnvVarMonitor | ||
| { | ||
| internal static TimeSpan CheckInterval = TimeSpan.FromSeconds(30); | ||
| internal static DateTime LastCheckTime = DateTime.MinValue; |
There was a problem hiding this comment.
Nit: private (unless you need to change it in unit tests.)
There was a problem hiding this comment.
CheckInterval can be private, NextCheckTime internal to allow tests to work - added a line comment to call this intention out.
| /// <summary> | ||
| /// Environment variables tracked by this monitor. | ||
| /// </summary> | ||
| internal static Dictionary<string, string> CheckedValues = new Dictionary<string, string>() |
There was a problem hiding this comment.
Nit: private static readonly (unless you need to change it in unit tests.)
There was a problem hiding this comment.
Agreed, done. I am always thrown by the readonly keyword with containers...
| { | ||
| { "WEBSITE_SITE_NAME", string.Empty }, | ||
| { "WEBSITE_HOME_STAMPNAME", string.Empty }, | ||
| { "WEBSITE_HOSTNAME", string.Empty } |
There was a problem hiding this comment.
Nit: remove extra space (alignment)
There was a problem hiding this comment.
Done, this was breaking the build (stylecop).
|
Thanks for looking this over @pharring, exactly the feedback I was looking for (keeping perf in mind for this task is pretty important I think). @SergeyKanzhelev I am looking for feedback if this is a decent idea to pursue or not. In principle it should work with the idea presented, but I understand if you need to keep your PR review time streamlined - apologies for the noise! I will ensure it works in a test now and ping you for feedback once I've proven it out further. |
|
I gave a link to PR in Azure functions that fixing this issue. Problem there is that sandbox doesn't update every env variable after swap. So I'd like you to make sure it works |
|
@SergeyKanzhelev Please have a look at this now that I've got it a bit more put together. I've added some test methods to ensure they do what we want, and that the change satisfies the same demands the Web Functions PR did. |
| internal static DateTime NextCheckTime = DateTime.MinValue; | ||
|
|
||
| // how often we allow the code to re-check the environment | ||
| private static readonly TimeSpan CheckInterval = TimeSpan.FromSeconds(30); |
There was a problem hiding this comment.
Could do, not sure how much value would be there. I propose we raise an issue and chat about it for the next release.
There was a problem hiding this comment.
Let's not overexpose API we are not certain in and may want to pull in the very next PR. We can make it configurable later if we stick with this solution, we cannot unmake public API once it's in stable release without the breaking change.
- Add heartbeat provider for Web Apps/App Services - Add monitor for App Services environment variables (which can change during the runtime of an AppServices app) - Ensure adequate testing is added, update current Env Var tests to be testable in a parallel environment
Dmitry-Matveev
left a comment
There was a problem hiding this comment.
Asynchronous solution would seem better rather than modifying values from Telemetry Initializer. However, this solution will work as well. Discussed options offline with Derek, More comments below.
| { | ||
| return Environment.GetEnvironmentVariable(WebAppHostNameEnvironmentVariable) ?? string.Empty; | ||
| string nodeName = string.Empty; | ||
| AppServiceEnvVarMonitor.GetUpdatedEnvironmentVariable(WebAppHostNameEnvironmentVariable, ref nodeName); |
There was a problem hiding this comment.
This is no longer lazy initialized and we've added ~3 extra stack frames to every request/dependency in the customer app. Variable will be read synchronously every 30 seconds (may be fine if we do not Expand..() it, though).
We may think of an asynchronous approach here. Discussed offline with Derek.
| { | ||
| { "WEBSITE_SITE_NAME", string.Empty }, | ||
| { "WEBSITE_HOME_STAMPNAME", string.Empty }, | ||
| { "WEBSITE_HOSTNAME", string.Empty } |
There was a problem hiding this comment.
In comments for environment variable extraction in this PR, it's noted that WEBSITE_HOSTNAME is not a reliable source:
//...refactored so that it did not use WEBSITE_HOSTNAME, which is determined to be unreliable for functions during slot swaps.
Do we want to rely on that field, or we may use some tricks, e.g. from the same PR to build something more reliable from what we have.
There was a problem hiding this comment.
I say we should resort to these tactics if we have an issue or have proof that App Services are affected by the same failing that Azure Functions are. I have put an issue together to verify that we can detect slot swap using only WEBSITE_HOSTNAME, and to update to using the WEBSITE_SITE_NAME + WEBSITE_SLOT_NAME if the need arises. Note that I've included the WEBSITE_SLOT_NAME in the list of environment variables that the monitor watches for now.
| internal static DateTime NextCheckTime = DateTime.MinValue; | ||
|
|
||
| // how often we allow the code to re-check the environment | ||
| private static readonly TimeSpan CheckInterval = TimeSpan.FromSeconds(30); |
There was a problem hiding this comment.
Let's not overexpose API we are not certain in and may want to pull in the very next PR. We can make it configurable later if we stick with this solution, we cannot unmake public API once it's in stable release without the breaking change.
- Use env var monitor to check for udpates to environment in controlled/minimal fashion - default to 30 second interval for checking the changes to environment - corrections for stylecop
|
I have merged this change into PR #869. Please move comments and issues to that PR. |
Add heartbeat provider for Azure App Services (in particular, Web Apps) that will add some infrastructure-identifying properties. - Solves issue #648, #868, and #872. - Both `AzureWebAppRoleEnvironment` and `AppServiceHeartbeatTelemetryModule` need to update their telemetry cache whenever the environment chances (ie, slot swap). `AppServiceEnvironmentVariableMonitor` solves this. - Keep the value of WEBSITE_SITE_NAME and other App Services values current during runtime - Merge PR #870 and #869, regarding heartbeat providers for App Services - Ensure adequate testing is added, update current Env Var tests to be testable in a parallel environment - `EnvironmentVariableMonitor` only updates the environment variables at set intervals, its subscribers only update when they need to. - Disable monitor if we don't detect that we are in Azure App Service environment, and on SecurityExceptions, disable the monitor altogether
Corrects aspects of issue #868, further to PR #869.
Use to keep the value of WEBSITE_SITE_NAME and other App Services values current during runtime, as these values can change when swapping App Service applications from one slot to the next.
Initial PR to bring discussion on the fix, and get some feedback before pushing to Heartbeat update as well.