Skip to content

Commit

Permalink
Use Singleton Metrics Provider for Listener (#285)
Browse files Browse the repository at this point in the history
* initial commit

* update version

* add nullable makr

* udpate test

* remove back to v1.5.1

* Fix typo in CHANGELOG.md entry

* Update Directory.Packages.props

* update scalemonitor and target scaler per functionid

* update comments

* update by comments:

* add query metrics throttle

* refactor code a little bit:
  • Loading branch information
nytian authored Feb 12, 2025
1 parent ce114d5 commit 7843abe
Show file tree
Hide file tree
Showing 6 changed files with 33 additions and 30 deletions.
3 changes: 2 additions & 1 deletion CHANGELOG.md
Original file line number Diff line number Diff line change
@@ -1,9 +1,10 @@
# Changelog

## v1.5.1 (Unreleased)
## v1.5.1

### Updates

* Use Singelton metrics provider instead of IScaleMonitor and ITargetScaler ([#285]https://github.com/microsoft/durabletask-mssql/pull/285)
* Updated repo to use central package management
* Resolved multiple CVEs in dependencies

Expand Down
Binary file modified Directory.Packages.props
Binary file not shown.
21 changes: 8 additions & 13 deletions src/DurableTask.SqlServer.AzureFunctions/SqlDurabilityProvider.cs
Original file line number Diff line number Diff line change
Expand Up @@ -22,10 +22,7 @@ class SqlDurabilityProvider : DurabilityProvider
readonly SqlDurabilityOptions durabilityOptions;
readonly SqlOrchestrationService service;

SqlScaleMonitor? scaleMonitor;
#if FUNCTIONS_V4
SqlTargetScaler? targetScaler;
#endif
SqlMetricsProvider? singletonSqlMetricsProvider;

public SqlDurabilityProvider(
SqlOrchestrationService service,
Expand Down Expand Up @@ -200,13 +197,12 @@ public override bool TryGetScaleMonitor(
string storageConnectionString,
out IScaleMonitor scaleMonitor)
{
if (this.scaleMonitor == null)
if (this.singletonSqlMetricsProvider == null)
{
var sqlMetricsProvider = new SqlMetricsProvider(this.service);
this.scaleMonitor = new SqlScaleMonitor(hubName, sqlMetricsProvider);
this.singletonSqlMetricsProvider = new SqlMetricsProvider(this.service);
}

scaleMonitor = this.scaleMonitor;
scaleMonitor = new SqlScaleMonitor(functionId, hubName, this.singletonSqlMetricsProvider);

return true;
}

Expand All @@ -218,13 +214,12 @@ public override bool TryGetTargetScaler(
string connectionName,
out ITargetScaler targetScaler)
{
if (this.targetScaler == null)
if (this.singletonSqlMetricsProvider == null)
{
var sqlMetricsProvider = new SqlMetricsProvider(this.service);
this.targetScaler = new SqlTargetScaler(hubName, sqlMetricsProvider);
this.singletonSqlMetricsProvider = new SqlMetricsProvider(this.service);
}

targetScaler = this.targetScaler;
targetScaler = new SqlTargetScaler(functionId, this.singletonSqlMetricsProvider);
return true;
}
#endif
Expand Down
22 changes: 16 additions & 6 deletions src/DurableTask.SqlServer.AzureFunctions/SqlMetricsProvider.cs
Original file line number Diff line number Diff line change
Expand Up @@ -3,12 +3,15 @@

namespace DurableTask.SqlServer.AzureFunctions
{
using System;
using System.Threading;
using System.Threading.Tasks;

public class SqlMetricsProvider
{
readonly SqlOrchestrationService service;
DateTime metricsTimeStamp = DateTime.MinValue;
SqlScaleMetric? metrics;

public SqlMetricsProvider(SqlOrchestrationService service)
{
Expand All @@ -17,13 +20,20 @@ public SqlMetricsProvider(SqlOrchestrationService service)

public virtual async Task<SqlScaleMetric> GetMetricsAsync(int? previousWorkerCount = null)
{
// GetRecommendedReplicaCountAsync will write a trace if the recommendation results
// in a worker count that is different from the worker count we pass in as an argument.
int recommendedReplicaCount = await this.service.GetRecommendedReplicaCountAsync(
previousWorkerCount,
CancellationToken.None);
// We only want to query the metrics every 5 seconds.
if (this.metrics == null || DateTime.UtcNow >= this.metricsTimeStamp.AddSeconds(5))
{
// GetRecommendedReplicaCountAsync will write a trace if the recommendation results
// in a worker count that is different from the worker count we pass in as an argument.
int recommendedReplicaCount = await this.service.GetRecommendedReplicaCountAsync(
previousWorkerCount,
CancellationToken.None);

return new SqlScaleMetric { RecommendedReplicaCount = recommendedReplicaCount };
this.metricsTimeStamp = DateTime.UtcNow;
this.metrics = new SqlScaleMetric { RecommendedReplicaCount = recommendedReplicaCount };
}

return this.metrics;
}
}
}
9 changes: 4 additions & 5 deletions src/DurableTask.SqlServer.AzureFunctions/SqlScaleMonitor.cs
Original file line number Diff line number Diff line change
Expand Up @@ -23,14 +23,13 @@ class SqlScaleMonitor : IScaleMonitor<SqlScaleMetric>

int? previousWorkerCount = -1;

public SqlScaleMonitor(string taskHubName, SqlMetricsProvider sqlMetricsProvider)
public SqlScaleMonitor(string functionId, 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"}";
// Scalers in Durable Functions is per function ids. And scalers share the same sqlMetricsProvider in the same taskhub.
string id = $"{functionId}-DurableTask-SqlServer:{taskHubName ?? "default"}";

#if FUNCTIONS_V4
this.Descriptor = new ScaleMonitorDescriptor(id: id, functionId: id);
this.Descriptor = new ScaleMonitorDescriptor(id: id, functionId: functionId);
#else
this.Descriptor = new ScaleMonitorDescriptor(id);
#endif
Expand Down
8 changes: 3 additions & 5 deletions src/DurableTask.SqlServer.AzureFunctions/SqlTargetScaler.cs
Original file line number Diff line number Diff line change
Expand Up @@ -12,14 +12,12 @@ public class SqlTargetScaler : ITargetScaler
{
readonly SqlMetricsProvider sqlMetricsProvider;

public SqlTargetScaler(string taskHubName, SqlMetricsProvider sqlMetricsProvider)
public SqlTargetScaler(string functionId, SqlMetricsProvider sqlMetricsProvider)
{
this.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"}";
this.TargetScalerDescriptor = new TargetScalerDescriptor(id);
// Scalers in Durable Functions is per function ids. And scalers share the same sqlMetricsProvider in the same taskhub.
this.TargetScalerDescriptor = new TargetScalerDescriptor(functionId);
}

public TargetScalerDescriptor TargetScalerDescriptor { get; }
Expand Down

0 comments on commit 7843abe

Please sign in to comment.