-
Notifications
You must be signed in to change notification settings - Fork 33
/
Copy pathSqlScaleMonitor.cs
84 lines (70 loc) · 3.05 KB
/
SqlScaleMonitor.cs
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
// Copyright (c) Microsoft Corporation.
// Licensed under the MIT License.
namespace DurableTask.SqlServer.AzureFunctions
{
using System;
using System.Collections.Generic;
using System.Linq;
using System.Threading;
using System.Threading.Tasks;
using Microsoft.Azure.WebJobs.Host.Scale;
/// <summary>
/// Azure Functions scale monitor implementation for the Durable Functions SQL backend.
/// </summary>
class SqlScaleMonitor : IScaleMonitor<SqlScaleMetric>
{
static readonly ScaleStatus ScaleInVote = new ScaleStatus { Vote = ScaleVote.ScaleIn };
static readonly ScaleStatus NoScaleVote = new ScaleStatus { Vote = ScaleVote.None };
static readonly ScaleStatus ScaleOutVote = new ScaleStatus { Vote = ScaleVote.ScaleOut };
readonly SqlMetricsProvider metricsProvider;
int? previousWorkerCount = -1;
public SqlScaleMonitor(string taskHubName, SqlMetricsProvider sqlMetricsProvider)
{
// Scalers in Durable Functions are shared for all functions in the same task hub.
// So instead of using a function ID, we use the task hub name as the basis for the descriptor ID.
string id = $"DurableTask-SqlServer:{taskHubName ?? "default"}";
#if FUNCTIONS_V4
this.Descriptor = new ScaleMonitorDescriptor(id: id, functionId: id);
#else
this.Descriptor = new ScaleMonitorDescriptor(id);
#endif
this.metricsProvider = sqlMetricsProvider ?? throw new ArgumentNullException(nameof(sqlMetricsProvider));
}
/// <inheritdoc />
public ScaleMonitorDescriptor Descriptor { get; }
/// <inheritdoc />
async Task<ScaleMetrics> IScaleMonitor.GetMetricsAsync() => await this.GetMetricsAsync();
/// <inheritdoc />
public async Task<SqlScaleMetric> GetMetricsAsync()
{
return await this.metricsProvider.GetMetricsAsync(this.previousWorkerCount);
}
/// <inheritdoc />
ScaleStatus IScaleMonitor.GetScaleStatus(ScaleStatusContext context) =>
this.GetScaleStatusCore(context.WorkerCount, context.Metrics.Cast<SqlScaleMetric>());
/// <inheritdoc />
public ScaleStatus GetScaleStatus(ScaleStatusContext<SqlScaleMetric> context) =>
this.GetScaleStatusCore(context.WorkerCount, context.Metrics);
ScaleStatus GetScaleStatusCore(int currentWorkerCount, IEnumerable<SqlScaleMetric> metrics)
{
SqlScaleMetric? mostRecentMetric = metrics.LastOrDefault();
if (mostRecentMetric == null)
{
return NoScaleVote;
}
this.previousWorkerCount = currentWorkerCount;
if (mostRecentMetric.RecommendedReplicaCount > currentWorkerCount)
{
return ScaleOutVote;
}
else if (mostRecentMetric.RecommendedReplicaCount < currentWorkerCount)
{
return ScaleInVote;
}
else
{
return NoScaleVote;
}
}
}
}