Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Pushing DfMon Isolated for MSSQL as a separate NuGet package #234

Open
wants to merge 9 commits into
base: main
Choose a base branch
from
Open
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension


Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
15 changes: 14 additions & 1 deletion .github/workflows/push-to-nuget.yml
Original file line number Diff line number Diff line change
Expand Up @@ -7,7 +7,7 @@ on:
jobs:
build:

runs-on: ubuntu-latest
runs-on: ubuntu-20.04

steps:
- uses: actions/checkout@v4
Expand Down Expand Up @@ -56,29 +56,42 @@ jobs:
run: dotnet publish durablefunctionsmonitor.dotnetbackend --output drop/durablefunctionsmonitor.dotnetbackend/output
- name: dotnet publish durablefunctionsmonitor.dotnetisolated
run: dotnet publish durablefunctionsmonitor.dotnetisolated --output drop/durablefunctionsmonitor.dotnetisolated/output
- name: dotnet publish dotnetIsolated-mssql
run: dotnet publish custom-backends/dotnetIsolated-mssql --output drop/dotnetIsolated-mssql/output

# Building nuget packages

- name: copy LICENSE to durablefunctionsmonitor.dotnetbackend/output
run: cp LICENSE drop/durablefunctionsmonitor.dotnetbackend/output
- name: copy LICENSE.txt to durablefunctionsmonitor.dotnetisolated/output
run: cp durablefunctionsmonitor.dotnetisolated/LICENSE.txt drop/durablefunctionsmonitor.dotnetisolated/output
- name: copy LICENSE.txt to dotnetIsolated-mssql/output
run: cp durablefunctionsmonitor.dotnetisolated/LICENSE.txt drop/dotnetIsolated-mssql/output

- name: Install latest nuget.exe
uses: nuget/setup-nuget@v1.2.0
- name: package dotnetbackend into a Nuget package
run: nuget pack drop/durablefunctionsmonitor.dotnetbackend/output/nuspec.nuspec -OutputDirectory drop
- name: package dotnetisolated into a Nuget package
run: nuget pack drop/durablefunctionsmonitor.dotnetisolated/output/nuspec.nuspec -OutputDirectory drop
- name: package dotnetIsolated-mssql into a Nuget package
run: nuget pack drop/dotnetIsolated-mssql/output/nuspec.nuspec -OutputDirectory drop

# Pushing nuget packages

- name: push drop/DurableFunctionsMonitor.DotNetIsolated
env:
NUGET_API_KEY: ${{ secrets.NUGET_API_KEY }}
run: nuget push drop/DurableFunctionsMonitor.DotNetIsolated.*.nupkg -ApiKey $NUGET_API_KEY -src https://api.nuget.org/v3/index.json
if: false

- name: push drop/DurableFunctionsMonitor.DotNetBackend
env:
NUGET_API_KEY: ${{ secrets.NUGET_API_KEY }}
run: nuget push drop/DurableFunctionsMonitor.DotNetBackend.*.nupkg -ApiKey $NUGET_API_KEY -src https://api.nuget.org/v3/index.json
if: false

- name: push drop/DurableFunctionsMonitor.DotNetIsolated.MsSql
env:
NUGET_API_KEY: ${{ secrets.NUGET_API_KEY }}
run: nuget push drop/DurableFunctionsMonitor.DotNetIsolated.MsSql.*.nupkg -ApiKey $NUGET_API_KEY -src https://api.nuget.org/v3/index.json
2 changes: 1 addition & 1 deletion custom-backends/dotnetIsolated-mssql/.vscode/settings.json
Original file line number Diff line number Diff line change
@@ -1,5 +1,5 @@
{
"azureFunctions.deploySubpath": "bin/Release/net7.0/publish",
"azureFunctions.deploySubpath": "bin/Release/net8.0/publish",
"azureFunctions.projectLanguage": "C#",
"azureFunctions.projectRuntime": "~4",
"debug.internalConsoleOptions": "neverOpen",
Expand Down
2 changes: 1 addition & 1 deletion custom-backends/dotnetIsolated-mssql/.vscode/tasks.json
Original file line number Diff line number Diff line change
Expand Up @@ -59,7 +59,7 @@
"type": "func",
"dependsOn": "build (functions)",
"options": {
"cwd": "${workspaceFolder}/bin/Debug/net7.0"
"cwd": "${workspaceFolder}/bin/Debug/net8.0"
},
"command": "host start",
"isBackground": true,
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -8,13 +8,14 @@
</PropertyGroup>
<ItemGroup>
<PackageReference Include="DurableFunctionsMonitor.DotNetIsolated" Version="6.6.0" />
<PackageReference Include="Microsoft.Azure.Functions.Worker" Version="1.22.0" />
<PackageReference Include="Microsoft.Azure.Functions.Worker.Extensions.DurableTask" Version="1.1.3" />
<PackageReference Include="Microsoft.Azure.Functions.Worker.Extensions.DurableTask.SqlServer" Version="1.2.1" />
<PackageReference Include="Microsoft.Azure.Functions.Worker.Extensions.Http" Version="3.1.0" />
<PackageReference Include="Microsoft.Azure.Functions.Worker.Sdk" Version="1.17.2" />
<PackageReference Include="Microsoft.Data.SqlClient" Version="5.2.0" />
</ItemGroup>

<ItemGroup>
<ProjectReference Include="..\..\durablefunctionsmonitor.dotnetisolated.mssql\durablefunctionsmonitor.dotnetisolated.mssql.csproj" />
</ItemGroup>

<ItemGroup>
<None Update="host.json">
<CopyToOutputDirectory>PreserveNewest</CopyToOutputDirectory>
Expand All @@ -23,6 +24,9 @@
<CopyToOutputDirectory>PreserveNewest</CopyToOutputDirectory>
<CopyToPublishDirectory>Never</CopyToPublishDirectory>
</None>
<None Update="nuspec.nuspec">
<CopyToOutputDirectory>PreserveNewest</CopyToOutputDirectory>
</None>
</ItemGroup>
<ItemGroup>
<Using Include="System.Threading.ExecutionContext" Alias="ExecutionContext" />
Expand Down
228 changes: 3 additions & 225 deletions custom-backends/dotnetIsolated-mssql/Program.cs
Original file line number Diff line number Diff line change
Expand Up @@ -2,244 +2,22 @@
// Licensed under the MIT license.

using Microsoft.Extensions.Hosting;
using DurableFunctionsMonitor.DotNetIsolated;
using Microsoft.Data.SqlClient;
using Microsoft.DurableTask.Client;
using DurableFunctionsMonitor.DotNetIsolated.MsSql;

namespace Dfm.DotNetIsolatedMsSql
{
internal class Program
{
private static readonly string ConnString;
private static readonly string SchemaName = "dt";

static Program()
{
ConnString = Environment.GetEnvironmentVariable("DFM_SQL_CONNECTION_STRING")!;

// Getting custom schema name passed to us by VsCode ext
string? schemaName = Environment.GetEnvironmentVariable("AzureFunctionsJobHost__extensions__durableTask__storageProvider__schemaName");
if (!string.IsNullOrEmpty(schemaName))
{
SchemaName = schemaName;
}
}

private static void Main(string[] args)
{
var host = new HostBuilder()
.ConfigureFunctionsWorkerDefaults((hostBuilderContext, workerAppBuilder) =>
{
workerAppBuilder.UseDurableFunctionsMonitor((settings, extPoints) =>
{
extPoints.GetInstanceHistoryRoutine = (client, connName, hubName, instanceId) => Task.FromResult(GetInstanceHistory(client, connName, hubName, instanceId));
extPoints.GetParentInstanceIdRoutine = GetParentInstanceId;
extPoints.GetTaskHubNamesRoutine = GetTaskHubNames;
});
workerAppBuilder.UseDurableFunctionsMonitorWithMsSqlDurability();
})
.Build();

host.Run();
}

/// <summary>
/// Custom routine for fetching Task Hub names
/// </summary>
public static async Task<IEnumerable<string>> GetTaskHubNames(string connName)
{
var result = new List<string>();

string sql =
$@"SELECT DISTINCT
i.TaskHub as TaskHub
FROM
[{SchemaName}].Instances i";

using (var conn = new SqlConnection(ConnString))
{
conn.Open();

using (var cmd = new SqlCommand(sql, conn))
{
using (var reader = cmd.ExecuteReader())
{
while (await reader.ReadAsync())
{
result.Add(reader["TaskHub"].ToString()!);
}
}
}
}

return result;
}

/// <summary>
/// Custom routine for fetching parent orchestration id
/// </summary>
public static async Task<string?> GetParentInstanceId(DurableTaskClient durableClient, string connName, string hubName, string instanceId)
{
string sql =
$@"SELECT
i.ParentInstanceID as ParentInstanceID
FROM
[{SchemaName}].Instances i
WHERE
i.InstanceID = @OrchestrationInstanceId AND i.TaskHub = @TaskHub";

using (var conn = new SqlConnection(ConnString))
{
conn.Open();

using (var cmd = new SqlCommand(sql, conn))
{
cmd.Parameters.AddWithValue("@OrchestrationInstanceId", instanceId);
cmd.Parameters.AddWithValue("@TaskHub", hubName);
using (var reader = cmd.ExecuteReader())
{
if (await reader.ReadAsync())
{
var parentInstanceId = reader["ParentInstanceID"];
if (parentInstanceId != null)
{
string? parentInstanceIdString = parentInstanceId.ToString();
if (!string.IsNullOrWhiteSpace(parentInstanceIdString))
{
return parentInstanceIdString;
}
}
}
}
}
}

return null;
}

/// <summary>
/// Custom routine for fetching orchestration history
/// </summary>
public static IEnumerable<HistoryEvent> GetInstanceHistory(DurableTaskClient durableClient, string connName, string hubName, string instanceId)
{
string sql =
$@"SELECT
IIF(h2.TaskID IS NULL, h.Timestamp, h2.Timestamp) as Timestamp,
IIF(h2.TaskID IS NULL, h.EventType, h2.EventType) as EventType,
h.TaskID as EventId,
h.Name as Name,
IIF(h2.TaskID IS NULL, NULL, h.Timestamp) as ScheduledTime,
p1.Text as Input,
p2.Text as Result,
p2.Reason as Details,
cih.InstanceID as SubOrchestrationId
FROM
[{SchemaName}].History h
LEFT JOIN
[{SchemaName}].History h2
ON
(
h.EventType IN ('TaskScheduled', 'SubOrchestrationInstanceCreated')
AND
h2.EventType IN ('SubOrchestrationInstanceCompleted', 'SubOrchestrationInstanceFailed', 'TaskCompleted', 'TaskFailed')
AND
h.InstanceID = h2.InstanceID AND h.ExecutionID = h2.ExecutionID AND h.TaskHub = h2.TaskHub AND h.TaskID = h2.TaskID AND h.SequenceNumber != h2.SequenceNumber
)
LEFT JOIN
[{SchemaName}].Payloads p1
ON
p1.PayloadID = h.DataPayloadID AND p1.TaskHub = h.TaskHub AND p1.InstanceID = h.InstanceID
LEFT JOIN
[{SchemaName}].Payloads p2
ON
p2.PayloadID = h2.DataPayloadID AND p2.TaskHub = h2.TaskHub AND p2.InstanceID = h2.InstanceID
LEFT JOIN
(
select
cii.ParentInstanceID,
cii.InstanceID,
cii.TaskHub,
chh.TaskID
from
[{SchemaName}].Instances cii
INNER JOIN
[{SchemaName}].History chh
ON
(chh.InstanceID = cii.InstanceID AND chh.TaskHub = cii.TaskHub AND chh.EventType = 'ExecutionStarted')
) cih
ON
(cih.ParentInstanceID = h.InstanceID AND cih.TaskHub = h.TaskHub AND cih.TaskID = h.TaskID AND h.EventType = 'SubOrchestrationInstanceCreated')
WHERE
h.EventType IN
(
'ExecutionStarted', 'ExecutionCompleted', 'ExecutionFailed', 'ExecutionTerminated', 'TaskScheduled', 'SubOrchestrationInstanceCreated',
'ContinueAsNew', 'TimerCreated', 'TimerFired', 'EventRaised', 'EventSent'
)
AND
h.InstanceID = @OrchestrationInstanceId AND h.TaskHub = @TaskHub
ORDER BY
h.SequenceNumber";


using (var conn = new SqlConnection(ConnString))
{
conn.Open();

using (var cmd = new SqlCommand(sql, conn))
{
cmd.Parameters.AddWithValue("@OrchestrationInstanceId", instanceId);
cmd.Parameters.AddWithValue("@TaskHub", hubName);
using (var reader = cmd.ExecuteReader())
{
// Memorizing 'ExecutionStarted' event, to further correlate with 'ExecutionCompleted'
DateTimeOffset? executionStartedTimestamp = null;

while (reader.Read())
{
var evt = ToHistoryEvent(reader, executionStartedTimestamp);

if (evt.EventType == "ExecutionStarted")
{
executionStartedTimestamp = evt.Timestamp;
}

yield return evt;
}
}
}
}
}

private static HistoryEvent ToHistoryEvent(SqlDataReader reader, DateTimeOffset? executionStartTime)
{
var evt = new HistoryEvent
{
Timestamp = ((DateTime)reader["Timestamp"]).ToUniversalTime(),
EventType = reader["EventType"].ToString(),
EventId = reader["EventId"] is DBNull ? null : (int?)reader["EventId"],
Name = reader["Name"].ToString(),
Input = reader["Input"] is DBNull ? null : reader["Input"].ToString(),
Result = reader["Result"].ToString(),
Details = reader["Details"].ToString(),
SubOrchestrationId = reader["SubOrchestrationId"].ToString(),
};

var rawScheduledTime = reader["ScheduledTime"];
if (!(rawScheduledTime is DBNull))
{
evt.ScheduledTime = ((DateTime)rawScheduledTime).ToUniversalTime();
}
else if (evt.EventType == "ExecutionCompleted")
{
evt.ScheduledTime = executionStartTime?.ToUniversalTime();
}

if (evt.ScheduledTime.HasValue)
{
evt.DurationInMs = (evt.Timestamp - evt.ScheduledTime.Value).TotalMilliseconds;
}

return evt;
}
}
}

}
29 changes: 29 additions & 0 deletions custom-backends/dotnetIsolated-mssql/nuspec.nuspec
Original file line number Diff line number Diff line change
@@ -0,0 +1,29 @@
<?xml version="1.0"?>
<package xmlns="http://schemas.microsoft.com/packaging/2010/07/nuspec.xsd">
<metadata minClientVersion="2.5">
<id>DurableFunctionsMonitor.DotNetIsolated.MsSql</id>
<version>6.6.0-beta4</version>
<requireLicenseAcceptance>false</requireLicenseAcceptance>
<description>DurableFunctionsMonitor.DotNetIsolated.MsSql</description>
<authors>DurableFunctionsMonitor</authors>
<repository type="git" url="https://github.com/microsoft/DurableFunctionsMonitor" />
<license type="file">LICENSE.txt</license>

<dependencies>
<dependency id="DurableFunctionsMonitor.DotNetIsolated" version="6.6.0" />
<dependency id="Microsoft.Azure.Functions.Worker.Extensions.DurableTask.SqlServer" version="1.2.1" />
<dependency id="Microsoft.Data.SqlClient" version="5.2.0" />
</dependencies>

</metadata>

<files>
<file src="..\output\durablefunctionsmonitor.dotnetisolated.core.dll" target="lib/netcoreapp2.1" />
<file src="..\output\durablefunctionsmonitor.dotnetisolated.mssql.dll" target="lib/netcoreapp2.1" />
<file src="..\output\durablefunctionsmonitor.dotnetisolated.mssql.xml" target="lib/netcoreapp2.1" />
<file src="..\..\durablefunctionsmonitor.dotnetisolated\durablefunctionsmonitor.dotnetisolated.targets" target="build" />
<file src="..\output\*" target="/" />
<file src="..\output\.azurefunctions\**" target="/.azurefunctions" />
<file src="..\output\DfmStatics\**" target="/DfmStatics" />
</files>
</package>
Loading
Loading