{"id":18397217,"url":"https://github.com/intellitect/intellitect.aspnetcore.signalr.sqlserver","last_synced_at":"2025-10-11T08:32:34.931Z","repository":{"id":147151496,"uuid":"405267242","full_name":"IntelliTect/IntelliTect.AspNetCore.SignalR.SqlServer","owner":"IntelliTect","description":"A Microsoft SQL Server backplane for ASP.NET Core SignalR.","archived":false,"fork":false,"pushed_at":"2025-10-02T22:03:53.000Z","size":1055,"stargazers_count":42,"open_issues_count":2,"forks_count":8,"subscribers_count":8,"default_branch":"master","last_synced_at":"2025-10-02T23:36:29.653Z","etag":null,"topics":["aspnetcore","signalr","sql-server"],"latest_commit_sha":null,"homepage":"","language":"C#","has_issues":true,"has_wiki":null,"has_pages":null,"mirror_url":null,"source_name":null,"license":"apache-2.0","status":null,"scm":"git","pull_requests_enabled":true,"icon_url":"https://github.com/IntelliTect.png","metadata":{"files":{"readme":"README.md","changelog":null,"contributing":null,"funding":null,"license":"LICENSE.txt","code_of_conduct":null,"threat_model":null,"audit":null,"citation":null,"codeowners":null,"security":null,"support":null,"governance":null,"roadmap":null,"authors":null,"dei":null,"publiccode":null,"codemeta":null,"zenodo":null,"notice":null,"maintainers":null,"copyright":null,"agents":null,"dco":null,"cla":null}},"created_at":"2021-09-11T02:52:17.000Z","updated_at":"2025-10-02T22:03:56.000Z","dependencies_parsed_at":"2025-10-02T23:26:35.402Z","dependency_job_id":"69642f1d-a024-4782-a634-74a7cf614b7e","html_url":"https://github.com/IntelliTect/IntelliTect.AspNetCore.SignalR.SqlServer","commit_stats":null,"previous_names":[],"tags_count":10,"template":false,"template_full_name":null,"purl":"pkg:github/IntelliTect/IntelliTect.AspNetCore.SignalR.SqlServer","repository_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories/IntelliTect%2FIntelliTect.AspNetCore.SignalR.SqlServer","tags_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories/IntelliTect%2FIntelliTect.AspNetCore.SignalR.SqlServer/tags","releases_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories/IntelliTect%2FIntelliTect.AspNetCore.SignalR.SqlServer/releases","manifests_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories/IntelliTect%2FIntelliTect.AspNetCore.SignalR.SqlServer/manifests","owner_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/owners/IntelliTect","download_url":"https://codeload.github.com/IntelliTect/IntelliTect.AspNetCore.SignalR.SqlServer/tar.gz/refs/heads/master","sbom_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories/IntelliTect%2FIntelliTect.AspNetCore.SignalR.SqlServer/sbom","scorecard":null,"host":{"name":"GitHub","url":"https://github.com","kind":"github","repositories_count":279006611,"owners_count":26084148,"icon_url":"https://github.com/github.png","version":null,"created_at":"2022-05-30T11:31:42.601Z","updated_at":"2022-07-04T15:15:14.044Z","status":"online","status_checked_at":"2025-10-11T02:00:06.511Z","response_time":55,"last_error":null,"robots_txt_status":"success","robots_txt_updated_at":"2025-07-24T06:49:26.215Z","robots_txt_url":"https://github.com/robots.txt","online":true,"can_crawl_api":true,"host_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub","repositories_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories","repository_names_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repository_names","owners_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/owners"}},"keywords":["aspnetcore","signalr","sql-server"],"created_at":"2024-11-06T02:16:19.401Z","updated_at":"2025-10-11T08:32:34.916Z","avatar_url":"https://github.com/IntelliTect.png","language":"C#","funding_links":[],"categories":[],"sub_categories":[],"readme":"# IntelliTect.AspNetCore.SignalR.SqlServer\n\nA Microsoft SQL Server backplane for ASP.NET Core SignalR.\n\n[![Nuget](https://img.shields.io/nuget/v/IntelliTect.AspNetCore.SignalR.SqlServer)](https://www.nuget.org/packages/IntelliTect.AspNetCore.SignalR.SqlServer/)\n\n\nThis project is largely based off of a fork of the [SignalR Core Redis provider](https://github.com/dotnet/aspnetcore/tree/main/src/SignalR/server/StackExchangeRedis), reworked to use the underlying concepts of the [classic ASP.NET SignalR SQL Server backplane](https://github.com/SignalR/SignalR/tree/main/src/Microsoft.AspNet.SignalR.SqlServer). This means it supports subscription-based messaging via SQL Server Service Broker, falling back on periodic polling when not available.\n\n\n## SQL Server Configuration\n\nFor optimal responsiveness and performance, [SQL Server Service Broker](https://docs.microsoft.com/en-us/sql/database-engine/configure-windows/sql-server-service-broker?view=sql-server-ver15) should be enabled on your database. NOTE: **Service Broker is not available on Azure SQL Database.** If you are running in Azure, consider a Redis or Azure SignalR Service backplane instead.\n\nIf Service Broker is not available, a fallback of periodic queries is used. This fallback querying happens very rapidly when messages are encountered, but slows down once traffic stops.\n\nYou can check if Service Broker is enabled with the following query:\n``` sql\nSELECT [name], [service_broker_guid], [is_broker_enabled]\nFROM [master].[sys].[databases]\n```\n\nTo enable it, execute the following against the database. Note that this requires an exclusive lock over the database:\n``` sql\nALTER DATABASE [DatabaseName] SET ENABLE_BROKER WITH NO_WAIT;\n```\n\nIf the above command does not work due to existing connections, try terminating existing sessions automatically using\n``` sql \nALTER DATABASE [DatabaseName] SET ENABLE_BROKER WITH ROLLBACK IMMEDIATE\n```\n\nYou can also set `AutoEnableServiceBroker = true` when configuring in your `Startup.cs`, but this requires that the application have permissions to do so and has the same caveats that there can be no other active database sessions.\n\n## Usage\n\n1. Install the `IntelliTect.AspNetCore.SignalR.SqlServer` NuGet package.\n2. In `ConfigureServices` in `Startup.cs`, configure SignalR with `.UseSqlServer()`:\n\n\nSimple configuration:\n``` cs\nservices\n    .AddSignalR()\n    .AddSqlServer(Configuration.GetConnectionString(\"Default\"));\n```\n\nAdvanced configuration:\n\n``` cs \nservices\n    .AddSignalR()\n    .AddSqlServer(o =\u003e\n    {\n        o.ConnectionString = Configuration.GetConnectionString(\"Default\");\n        // See above - attempts to enable Service Broker on the database at startup\n        // if not already enabled. Default false, as this can hang if the database has other sessions.\n        o.AutoEnableServiceBroker = true;\n        // Every hub has its own message table(s). \n        // This determines the part of the table named that is derived from the hub name.\n        // IF THIS IS NOT UNIQUE AMONG ALL HUBS, YOUR HUBS WILL COLLIDE AND MESSAGES MIX.\n        o.TableSlugGenerator = hubType =\u003e hubType.Name;\n        // The number of tables per Hub to use. Adding a few extra could increase throughput\n        // by reducing table contention, but all servers must agree on the number of tables used.\n        // If you find that you need to increase this, it is probably a hint that you need to switch to Redis.\n        o.TableCount = 1;\n        // The SQL Server schema to use for the backing tables for this backplane.\n        o.SchemaName = \"SignalRCore\";\n    });\n```\n\nAlternatively, you may configure `IntelliTect.AspNetCore.SignalR.SqlServer.SqlServerOptions` with [the Options pattern](https://docs.microsoft.com/en-us/aspnet/core/fundamentals/configuration/?view=aspnetcore-5.0).\n\n``` cs\nservices.Configure\u003cSqlServerOptions\u003e(Configuration.GetSection(\"SignalR:SqlServer\"));\n```\n\n## OpenTelemetry Support\n\nThis library includes OpenTelemetry instrumentation that wraps background database queries in activities, making them more easily identified and grouped in your collected telemetry.\n\n### Setup\n\nTo enable OpenTelemetry collection of these trace spans and metrics, add the source and meter to your configuration:\n\n``` cs\nbuilder.Services.AddOpenTelemetry()\n    .WithTracing(tracing =\u003e tracing\n        .AddSource(\"IntelliTect.AspNetCore.SignalR.SqlServer\")\n        // ... other instrumentation\n    )\n    .WithMetrics(metrics =\u003e metrics\n        .AddMeter(\"IntelliTect.AspNetCore.SignalR.SqlServer\")\n        // ... other instrumentation\n    );\n```\n\n### Activity Names\n\nThe library creates activities for the following operations:\n- `SignalR.SqlServer.Install` - Database schema installation/setup\n- `SignalR.SqlServer.Start` - Receiver startup operations\n- `SignalR.SqlServer.Listen` - Service Broker listening operations (database reads)\n- `SignalR.SqlServer.Poll` - Polling operations (database reads, when Service Broker is not used)\n- `SignalR.SqlServer.Publish` - Message publishing operations (database writes)\n\n### Metrics\n\nThe library also provides metrics to help monitor the health and performance of the SQL Server backplane:\n\n- `signalr.sqlserver.poll_delay` - Histogram showing the distribution of polling delay intervals, useful for understanding backoff patterns and system health\n- `signalr.sqlserver.query_duration` - Histogram tracking the duration of SQL Server query execution for reading messages\n- `signalr.sqlserver.rows_read_total` - Counter tracking the total number of message rows read from SQL Server\n- `signalr.sqlserver.rows_written_total` - Counter tracking the total number of message rows written to SQL Server\n\nThese metrics help you understand polling patterns, database performance, message throughput, and can be useful for tuning performance or identifying when Service Broker fallback to polling occurs.\n\n### Filtering Noise\n\nSince the SQL Server backplane performs frequent polling operations, you may want to filter out successful, fast queries to reduce trace noise. \n\nThe following example assumes using package `OpenTelemetry.Instrumentation.SqlClient \u003e= 1.12.0-beta.3` for SqlClient instrumentation. There are currently [4 different packages for SqlClient instrumentation](https://github.com/dotnet/aspire/issues/2427#issuecomment-3259572206), so your method of collecting or filtering the command details may vary if you're using Aspire's instrumentation or Azure Monitor's instrumentation. Be sure to update the CommandText filter if you customize the schema name:\n\n``` cs\nbuilder.Services.AddOpenTelemetry()\n    .WithTracing(tracing =\u003e tracing\n        .AddSqlClientInstrumentation()\n        .AddSource(\"IntelliTect.AspNetCore.SignalR.SqlServer\")\n        .AddProcessor\u003cSignalRTelemetryNoiseFilter\u003e()\n    );\n\ninternal sealed class SignalRTelemetryNoiseFilter : BaseProcessor\u003cActivity\u003e\n{\n    public override void OnEnd(Activity activity)\n    {\n        if (activity.Status != ActivityStatusCode.Error \u0026\u0026\n            activity.Duration.TotalMilliseconds \u003c 100 \u0026\u0026\n            (activity.GetTagItem(\"db.query.text\") ?? activity.GetTagItem(\"db.statement\")) is string command \u0026\u0026\n            command.StartsWith(\"SELECT [PayloadId], [Payload], [InsertedOn] FROM [SignalR]\"))\n        {\n            // Sample out successful and fast SignalR queries\n            activity.ActivityTraceFlags \u0026= ~ActivityTraceFlags.Recorded;\n        }\n    }\n}\n```\n\n## Caveats\n\nAs mentioned above, if SQL Server Service Broker is not available, messages will not always be transmitted immediately since a fallback of periodic querying must be used.\n\n### Performance\n\nThis is not the right solution for applications with a need for very high throughput, or very high degrees of scale-out. Consider Redis or Azure SignalR Service instead for such cases. You should always do an appropriate amount of testing to determine if a particular solution is suitable for your application. \n\nThe results of some ad-hoc performance testing yielded that you can expect about 1000 messages per second per table (setting `TableCount`). However, increasing table count does have diminishing returns; attempting to push 20,000 messages/sec with 20 tables had a throughput of only ~10,000 messages/sec. This was observed with a SQL Server instance and load generator running on the same machine, an i9 9900k with an SSD, with a message size of ~200 bytes. A Redis backplane on the same hardware sustained 20,000 messages per second without issue.\n\nDo note that a broadcast message is considered a single message. Any call to `SendAsync` within a hub is a single message.\n\n## License\n\n[Apache 2.0](./LICENSE.txt). \n\nCredit to Microsoft for both Microsoft.AspNet.SignalR.SqlServer and Microsoft.AspNetCore.SignalR.StackExchangeRedis, upon which this project is based.\n","project_url":"https://awesome.ecosyste.ms/api/v1/projects/github.com%2Fintellitect%2Fintellitect.aspnetcore.signalr.sqlserver","html_url":"https://awesome.ecosyste.ms/projects/github.com%2Fintellitect%2Fintellitect.aspnetcore.signalr.sqlserver","lists_url":"https://awesome.ecosyste.ms/api/v1/projects/github.com%2Fintellitect%2Fintellitect.aspnetcore.signalr.sqlserver/lists"}