2
2
// Licensed under the MIT License. See License.txt in the project root for license information.
3
3
4
4
using System ;
5
- using System . IO ;
6
5
using System . IO . Abstractions ;
7
- using System . Linq ;
8
6
using System . Threading ;
9
7
using System . Threading . Tasks ;
10
8
using Microsoft . Azure . WebJobs . Script . Diagnostics ;
11
- using Microsoft . Azure . WebJobs . Script . Diagnostics . Extensions ;
12
9
using Microsoft . Azure . WebJobs . Script . Metrics ;
13
10
using Microsoft . Azure . WebJobs . Script . WebHost . Configuration ;
14
11
using Microsoft . Extensions . Logging ;
15
12
using Microsoft . Extensions . Options ;
16
- using Newtonsoft . Json ;
17
13
18
14
namespace Microsoft . Azure . WebJobs . Script . WebHost . Metrics
19
15
{
20
- public class FlexConsumptionMetricsPublisher : IMetricsPublisher , IDisposable
16
+ public sealed partial class FlexConsumptionMetricsPublisher : IMetricsPublisher , IDisposable
21
17
{
22
18
private readonly IOptionsMonitor < StandbyOptions > _standbyOptions ;
23
19
private readonly FlexConsumptionMetricsPublisherOptions _options ;
24
20
private readonly IEnvironment _environment ;
25
21
private readonly ILogger < FlexConsumptionMetricsPublisher > _logger ;
26
22
private readonly IHostMetricsProvider _metricsProvider ;
27
- private readonly object _lock = new object ( ) ;
23
+ private readonly object _lock = new ( ) ;
28
24
private readonly IFileSystem _fileSystem ;
29
25
private readonly LegionMetricsFileManager _metricsFileManager ;
30
26
31
- private Timer _metricsPublisherTimer ;
32
- private bool _started = false ;
33
27
private DateTime _currentActivityIntervalStart ;
34
28
private DateTime _activityIntervalHighWatermark = DateTime . MinValue ;
35
- private ValueStopwatch _intervalStopwatch ;
36
29
private IDisposable _standbyOptionsOnChangeSubscription ;
37
- private TimeSpan _metricPublishInterval ;
38
- private TimeSpan _initialPublishDelay ;
39
30
private DateTime _lastPublishTime = DateTime . UtcNow ;
31
+ private Lifecycle _lifecycle ;
40
32
41
33
public FlexConsumptionMetricsPublisher ( IEnvironment environment , IOptionsMonitor < StandbyOptions > standbyOptions , IOptions < FlexConsumptionMetricsPublisherOptions > options ,
42
34
ILogger < FlexConsumptionMetricsPublisher > logger , IFileSystem fileSystem , IHostMetricsProvider metricsProvider )
@@ -71,29 +63,43 @@ public FlexConsumptionMetricsPublisher(IEnvironment environment, IOptionsMonitor
71
63
72
64
internal LegionMetricsFileManager MetricsFileManager => _metricsFileManager ;
73
65
66
+ private bool IsStarted => _lifecycle is not null ;
67
+
74
68
public void Start ( )
75
69
{
76
- Initialize ( ) ;
70
+ if ( _lifecycle is not null )
71
+ {
72
+ return ;
73
+ }
74
+
75
+ lock ( _lock )
76
+ {
77
+ if ( _lifecycle is not null )
78
+ {
79
+ return ;
80
+ }
81
+
82
+ IsAlwaysReady = _environment
83
+ . GetEnvironmentVariable ( EnvironmentSettingNames . FunctionsAlwaysReadyInstance ) == "1" ;
77
84
78
- _logger . LogInformation ( $ "Starting metrics publisher (AlwaysReady={ IsAlwaysReady } , MetricsPath='{ _metricsFileManager . MetricsFilePath } ').") ;
85
+ _logger . LogInformation (
86
+ $ "Starting metrics publisher (AlwaysReady={ IsAlwaysReady } ,"
87
+ + $ " MetricsPath='{ _metricsFileManager . MetricsFilePath } ').") ;
79
88
80
- _metricsPublisherTimer = new Timer ( OnFunctionMetricsPublishTimer , null , _initialPublishDelay , _metricPublishInterval ) ;
81
- _started = true ;
89
+ _lifecycle = new (
90
+ this ,
91
+ TimeSpan . FromMilliseconds ( _options . InitialPublishDelayMS ) ,
92
+ TimeSpan . FromMilliseconds ( _options . MetricsPublishIntervalMS ) ) ;
93
+ }
82
94
}
83
95
84
- /// <summary>
85
- /// Initialize any environmentally derived state after specialization, prior to starting the publisher.
86
- /// </summary>
87
- internal void Initialize ( )
96
+ public void Dispose ( )
88
97
{
89
- _metricPublishInterval = TimeSpan . FromMilliseconds ( _options . MetricsPublishIntervalMS ) ;
90
- _initialPublishDelay = TimeSpan . FromMilliseconds ( _options . InitialPublishDelayMS ) ;
91
- _intervalStopwatch = ValueStopwatch . StartNew ( ) ;
92
-
93
- IsAlwaysReady = _environment . GetEnvironmentVariable ( EnvironmentSettingNames . FunctionsAlwaysReadyInstance ) == "1" ;
98
+ Interlocked . Exchange ( ref _lifecycle , null ) ? . Dispose ( ) ;
99
+ Interlocked . Exchange ( ref _standbyOptionsOnChangeSubscription , null ) ? . Dispose ( ) ;
94
100
}
95
101
96
- internal async Task OnPublishMetrics ( DateTime now )
102
+ internal async Task OnPublishMetrics ( DateTime now , ValueStopwatch stopwatch )
97
103
{
98
104
try
99
105
{
@@ -122,7 +128,7 @@ internal async Task OnPublishMetrics(DateTime now)
122
128
{
123
129
metrics = new Metrics
124
130
{
125
- TotalTimeMS = ( long ) _intervalStopwatch . GetElapsedTime ( ) . TotalMilliseconds ,
131
+ TotalTimeMS = ( long ) stopwatch . GetElapsedTime ( ) . TotalMilliseconds ,
126
132
ExecutionCount = FunctionExecutionCount ,
127
133
ExecutionTimeMS = FunctionExecutionTimeMS ,
128
134
IsAlwaysReady = IsAlwaysReady ,
@@ -149,15 +155,6 @@ internal async Task OnPublishMetrics(DateTime now)
149
155
// ensure no background exceptions escape
150
156
_logger . LogError ( ex , $ "Error publishing metrics.") ;
151
157
}
152
- finally
153
- {
154
- _intervalStopwatch = ValueStopwatch . StartNew ( ) ;
155
- }
156
- }
157
-
158
- private async void OnFunctionMetricsPublishTimer ( object state )
159
- {
160
- await OnPublishMetrics ( DateTime . UtcNow ) ;
161
158
}
162
159
163
160
private void OnStandbyOptionsChange ( )
@@ -175,7 +172,7 @@ public void OnFunctionStarted(string functionName, string invocationId)
175
172
176
173
internal void OnFunctionStarted ( string functionName , string invocationId , DateTime now )
177
174
{
178
- if ( ! _started )
175
+ if ( ! IsStarted )
179
176
{
180
177
return ;
181
178
}
@@ -199,7 +196,7 @@ public void OnFunctionCompleted(string functionName, string invocationId)
199
196
200
197
internal void OnFunctionCompleted ( string functionName , string invocationId , DateTime now )
201
198
{
202
- if ( ! _started )
199
+ if ( ! IsStarted )
203
200
{
204
201
return ;
205
202
}
@@ -267,15 +264,6 @@ private static double RoundUp(double metric, int granularity)
267
264
return Math . Ceiling ( metric / granularity ) * granularity ;
268
265
}
269
266
270
- public void Dispose ( )
271
- {
272
- _metricsPublisherTimer ? . Dispose ( ) ;
273
- _metricsPublisherTimer = null ;
274
-
275
- _standbyOptionsOnChangeSubscription ? . Dispose ( ) ;
276
- _standbyOptionsOnChangeSubscription = null ;
277
- }
278
-
279
267
internal class Metrics
280
268
{
281
269
/// <summary>
0 commit comments