Octopus
Connection Configuration
The SqlServerPlugin retrieves the SQL Server connection string at runtime via ICredentialResolver. The connection string is never stored in plaintext config — only the credential ID is in appsettings.json.
How the Credential Resolver Works
1
appsettings.json contains only the credential ID
"ConnectionStringCredentialId": 1 — an integer reference to the credential store
2
OnStartAsync resolves the actual connection string
ICredentialResolver.GetPasswordAsync(credentialId) fetches the value from the encrypted credential store
3
DbContext is configured with the resolved connection string
The EF Core
DbContextOptions are built dynamically with the live connection string
4
Connection verified before accepting requests
A lightweight
CanConnectAsync() call confirms the server is reachable before startup completes
SqlServerPlugin OnRegister / OnStartAsync Internals
public class SqlServerPlugin : IOctopusPlugin
{
private SqlServerPluginConfig _config = null!;
public void OnRegister(IServiceCollection services, OctopusConfig config)
{
// Bind config — no connection string here, just the credential ID
_config = config.GetSection<SqlServerPluginConfig>("SqlServerPlugin");
services.AddOptions<SqlServerPluginConfig>()
.Bind(config.Configuration.GetSection("SqlServerPlugin"))
.ValidateDataAnnotations()
.ValidateOnStart();
// Register DbContext with a factory so the connection string is resolved lazily
services.AddDbContextFactory<OctopusDbContext>((sp, opt) =>
{
// The connection string is injected at factory invocation time, not here
});
// Register storage implementations
services.AddScoped<IEpisodicMemoryStore, SqlEpisodicMemoryStore>();
services.AddScoped<IProceduralMemoryStore, SqlProceduralMemoryStore>();
services.AddScoped<IAgentStore, SqlAgentStore>();
services.AddScoped<IAIFunctionStore, SqlAIFunctionStore>();
services.AddScoped<IAreaStore, SqlAreaStore>();
}
public async Task OnStartAsync(IServiceProvider sp, CancellationToken ct)
{
// Resolve the connection string from the credential store
var credResolver = sp.GetRequiredService<ICredentialResolver>();
var connectionString = await credResolver.GetPasswordAsync(_config.ConnectionStringCredentialId);
// Configure the DbContext factory with the live connection string
var optionsFactory = sp.GetRequiredService<IDbContextOptionsConfigurator<OctopusDbContext>>();
optionsFactory.Configure(opt =>
opt.UseSqlServer(connectionString, sql =>
{
sql.CommandTimeout(_config.CommandTimeoutSeconds);
if (_config.EnableRetryOnFailure)
sql.EnableRetryOnFailure(_config.MaxRetryCount,
TimeSpan.FromSeconds(_config.MaxRetryDelaySeconds), null);
}));
// Verify connectivity
using var scope = sp.CreateScope();
var db = scope.ServiceProvider.GetRequiredService<OctopusDbContext>();
if (!await db.Database.CanConnectAsync(ct))
throw new InvalidOperationException(
$"Cannot connect to Octopus SQL Server (credential {_config.ConnectionStringCredentialId}).");
// Apply pending migrations
if (_config.RunMigrationsOnStartup)
await db.Database.MigrateAsync(ct);
}
public Task OnStopAsync(CancellationToken ct) => Task.CompletedTask;
}
Supported Connection String Formats
| Scenario | Connection String Example |
|---|---|
| Windows Integrated Auth | Server=sql01;Database=OctopusAI;Integrated Security=True;TrustServerCertificate=True |
| SQL Server Auth | Server=sql01;Database=OctopusAI;User Id=octopus_app;Password=***;TrustServerCertificate=True |
| Azure SQL (managed identity) | Server=myserver.database.windows.net;Database=OctopusAI;Authentication=Active Directory Managed Identity |
| Azure SQL (connection string) | Server=tcp:myserver.database.windows.net,1433;Database=OctopusAI;User Id=octopus@myserver;Password=***;Encrypt=True |
| SQL Express (dev) | Server=(localdb)\mssqllocaldb;Database=OctopusAI;Trusted_Connection=True |
Never put the connection string in appsettings.json. Only the integer
ConnectionStringCredentialId belongs in config. The actual connection string, including the password, must live exclusively in the encrypted credential store.
Connection Pooling
EF Core uses ADO.NET connection pooling by default. The default pool size of 100 connections is appropriate for most deployments. For high-concurrency scenarios adjust the pool size in the connection string:
// Added to the connection string stored in the credential:
// Max Pool Size=200;Min Pool Size=5;Connection Timeout=30
Retry Policy
When EnableRetryOnFailure is true, the plugin applies SQL Server transient error retry via EF Core's built-in strategy. Retried error codes include connection failures, deadlocks, and timeout errors. The retry uses exponential backoff with jitter up to MaxRetryDelaySeconds.