Skip to content

Commit 4f319dd

Browse files
authored
HostMetrics published every 30 seconds via flex metrics publisher (#11019)
1 parent 4ba45d7 commit 4f319dd

File tree

4 files changed

+50
-3
lines changed

4 files changed

+50
-3
lines changed

release_notes.md

Lines changed: 2 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -12,4 +12,5 @@
1212
- Update Python Worker Version to [4.37.0](https://github.com/Azure/azure-functions-python-worker/releases/tag/4.37.0)
1313
- Add runtime and process metrics. (#11034)
1414
- Add `win-arm64` and `linux-arm64` to the list of PowerShell runtimes; added filter for `osx` RIDs (includes `osx-x64` and `osx-arm64`) (#11013)
15-
- Disable Diagnostic Events when Table Storage is not accessible (#10996)
15+
- Disable Diagnostic Events when Table Storage is not accessible (#10996)
16+
- Update flex metric publisher to publish every 30 seconds (regardless of actvity) (#11019)

src/WebJobs.Script.WebHost/Configuration/FlexConsumptionMetricsPublisherOptions.cs

Lines changed: 11 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -14,12 +14,14 @@ public class FlexConsumptionMetricsPublisherOptions
1414
internal const int DefaultMetricsPublishIntervalMS = 5000;
1515
internal const int DefaultMinimumActivityIntervalMS = 1000;
1616
internal const int DefaultMetricsGranularityMS = 100;
17+
internal const int DefaultKeepAliveIntervalMS = 30000;
1718

1819
public FlexConsumptionMetricsPublisherOptions()
1920
{
2021
MetricsPublishIntervalMS = DefaultMetricsPublishIntervalMS;
2122
MinimumActivityIntervalMS = DefaultMinimumActivityIntervalMS;
2223
MetricsGranularityMS = DefaultMetricsGranularityMS;
24+
KeepAliveIntervalMS = DefaultKeepAliveIntervalMS;
2325
InitialPublishDelayMS = Utility.ColdStartDelayMS;
2426

2527
// Default this to 15 minutes worth of files
@@ -66,5 +68,14 @@ public FlexConsumptionMetricsPublisherOptions()
6668
/// When over this limit, the oldest files will be deleted to make room for new files.
6769
/// </remarks>
6870
public int MaxFileCount { get; set; }
71+
72+
/// <summary>
73+
/// Gets or sets the maximum interval at which metrics are published.
74+
/// </summary>
75+
/// <remarks>
76+
/// This is required to ensure that we publish something even if there are no
77+
/// new metrics or activity to report so that we have a heartbeat.
78+
/// </remarks>
79+
public int KeepAliveIntervalMS { get; set; }
6980
}
7081
}

src/WebJobs.Script.WebHost/Metrics/FlexConsumptionMetricsPublisher.cs

Lines changed: 7 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -36,6 +36,7 @@ public class FlexConsumptionMetricsPublisher : IMetricsPublisher, IDisposable
3636
private IDisposable _standbyOptionsOnChangeSubscription;
3737
private TimeSpan _metricPublishInterval;
3838
private TimeSpan _initialPublishDelay;
39+
private DateTime _lastPublishTime = DateTime.UtcNow;
3940

4041
public FlexConsumptionMetricsPublisher(IEnvironment environment, IOptionsMonitor<StandbyOptions> standbyOptions, IOptions<FlexConsumptionMetricsPublisherOptions> options,
4142
ILogger<FlexConsumptionMetricsPublisher> logger, IFileSystem fileSystem, IHostMetricsProvider metricsProvider)
@@ -105,9 +106,12 @@ internal async Task OnPublishMetrics(DateTime now)
105106
}
106107
}
107108

108-
if (FunctionExecutionCount == 0 && FunctionExecutionTimeMS == 0 && !IsAlwaysReady && !_metricsProvider.HasMetrics())
109+
bool hasActivity = FunctionExecutionCount > 0 || FunctionExecutionTimeMS > 0 || _metricsProvider.HasMetrics();
110+
bool shouldForcePublish = (now - _lastPublishTime) >= TimeSpan.FromMilliseconds(_options.KeepAliveIntervalMS);
111+
112+
if (!hasActivity && !shouldForcePublish && !IsAlwaysReady)
109113
{
110-
// no activity to report
114+
// No activity and not time for keep-alive publish & not always ready
111115
return;
112116
}
113117

@@ -135,6 +139,7 @@ internal async Task OnPublishMetrics(DateTime now)
135139
}
136140

137141
FunctionExecutionTimeMS = FunctionExecutionCount = 0;
142+
_lastPublishTime = now;
138143
}
139144

140145
await _metricsFileManager.PublishMetricsAsync(metrics);

test/WebJobs.Script.Tests/Metrics/FlexConsumptionMetricsPublisherTests.cs

Lines changed: 30 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -111,6 +111,7 @@ public async Task OnPublishMetrics_WritesFileAndResetsCounts(bool isAlwaysReadyI
111111

112112
FlexConsumptionMetricsPublisher.Metrics metrics = null;
113113
FileInfo metricsFile = null;
114+
114115
if (!isAlwaysReadyInstance)
115116
{
116117
// don't expect a file to be written when no activity
@@ -531,6 +532,35 @@ public async Task OnPublishMetrics_OutstandingActivityIsPublished()
531532
Assert.Equal(2000, metrics.ExecutionTimeMS);
532533
}
533534

535+
[Fact]
536+
public async Task OnPublishMetrics_KeepAliveMetricsPublished_WhenNoActivity()
537+
{
538+
CleanupMetricsFiles();
539+
540+
var publisher = CreatePublisher();
541+
542+
DateTime now = DateTime.UtcNow;
543+
544+
// Should not publish because there is no activity and keepalive internal has not passed
545+
await publisher.OnPublishMetrics(now);
546+
var files = GetMetricsFilesSafe(_metricsFilePath);
547+
Assert.Equal(0, files.Length);
548+
549+
// Simulate 31 seconds passing with no function activity
550+
now = now.AddSeconds(31);
551+
552+
// Should publish as keepalive interval has passed
553+
await publisher.OnPublishMetrics(now);
554+
files = GetMetricsFilesSafe(_metricsFilePath);
555+
Assert.Equal(1, files.Length);
556+
557+
var metrics = await ReadMetricsAsync(files[0].FullName, deleteFile: true);
558+
559+
// We expect all activity values to be zero as there has been no activity
560+
Assert.Equal(0, metrics.ExecutionCount);
561+
Assert.Equal(0, metrics.ExecutionTimeMS);
562+
}
563+
534564
[Fact]
535565
public void OnFunctionCompleted_NoOutstandingInvocations_IgnoresEvent()
536566
{

0 commit comments

Comments
 (0)