95220e2ed6
The startup configuration only reads JELLYFIN_ prefixed environment variables, so the bare Jellyfin__TranscodeStore__* form used by the chart, the manifests and the README is dropped and the Redis store is never registered. Nothing logs the selected store, so the fallback is invisible. - Read bare Jellyfin__* variables into the Jellyfin:* configuration root - Keep an explicit JELLYFIN_ variable winning over the bare form - Log the selected transcode session store at startup - Ping Redis once at startup and log an unreachable store at Error - Log endpoints only, never the connection string
88 lines
3.4 KiB
C#
88 lines
3.4 KiB
C#
using System;
|
|
using System.Linq;
|
|
using Emby.Server.Implementations.MediaEncoding;
|
|
using MediaBrowser.Controller.MediaEncoding;
|
|
using Microsoft.Extensions.Configuration;
|
|
using Microsoft.Extensions.DependencyInjection;
|
|
using Microsoft.Extensions.Logging;
|
|
using StackExchange.Redis;
|
|
|
|
namespace Jellyfin.Server.Extensions;
|
|
|
|
/// <summary>
|
|
/// Extensions for registering the transcode session store.
|
|
/// </summary>
|
|
public static class TranscodeStoreServiceCollectionExtensions
|
|
{
|
|
/// <summary>
|
|
/// Registers the transcode session store, Redis-backed when a connection string is configured and
|
|
/// no-op otherwise, and reports the selected store at <see cref="LogLevel.Information"/>.
|
|
/// </summary>
|
|
/// <param name="serviceCollection">The service collection.</param>
|
|
/// <param name="configuration">The configuration to read <c>Jellyfin:TranscodeStore</c> from.</param>
|
|
/// <param name="logger">The logger to report the selected store on.</param>
|
|
/// <returns>The updated service collection.</returns>
|
|
public static IServiceCollection AddTranscodeSessionStore(
|
|
this IServiceCollection serviceCollection,
|
|
IConfiguration configuration,
|
|
ILogger logger)
|
|
{
|
|
ArgumentNullException.ThrowIfNull(configuration);
|
|
ArgumentNullException.ThrowIfNull(logger);
|
|
|
|
serviceCollection.Configure<TranscodeStoreOptions>(configuration.GetSection(TranscodeStoreOptions.ConfigurationSection));
|
|
|
|
var redisConnectionString = configuration[TranscodeStoreOptions.RedisConnectionStringKey];
|
|
if (string.IsNullOrEmpty(redisConnectionString))
|
|
{
|
|
logger.LogInformation(
|
|
"Transcode session store: {Store}. Cross-pod transcode takeover is off; set {Key} to enable it.",
|
|
nameof(NullTranscodeSessionStore),
|
|
TranscodeStoreOptions.RedisConnectionStringKey);
|
|
|
|
return serviceCollection.AddSingleton<ITranscodeSessionStore, NullTranscodeSessionStore>();
|
|
}
|
|
|
|
logger.LogInformation(
|
|
"Transcode session store: {Store} on {Endpoints}.",
|
|
nameof(RedisTranscodeSessionStore),
|
|
DescribeEndpoints(redisConnectionString));
|
|
|
|
serviceCollection.AddSingleton<IConnectionMultiplexer>(sp =>
|
|
{
|
|
try
|
|
{
|
|
return ConnectionMultiplexer.Connect(redisConnectionString);
|
|
}
|
|
catch (Exception ex)
|
|
{
|
|
sp.GetRequiredService<ILogger<CoreAppHost>>()
|
|
.LogError(ex, "Failed to connect to Redis. Check the {Key} configuration.", TranscodeStoreOptions.RedisConnectionStringKey);
|
|
throw;
|
|
}
|
|
});
|
|
serviceCollection.AddSingleton<ITranscodeSessionStore, RedisTranscodeSessionStore>();
|
|
serviceCollection.AddHostedService<TranscodeStoreConnectivityProbe>();
|
|
|
|
return serviceCollection;
|
|
}
|
|
|
|
/// <summary>
|
|
/// Renders the endpoints of a connection string for logging. The connection string itself is never
|
|
/// logged because it can carry a password.
|
|
/// </summary>
|
|
private static string DescribeEndpoints(string redisConnectionString)
|
|
{
|
|
try
|
|
{
|
|
return string.Join(
|
|
',',
|
|
ConfigurationOptions.Parse(redisConnectionString).EndPoints.Select(endpoint => endpoint.ToString()));
|
|
}
|
|
catch (ArgumentException)
|
|
{
|
|
return "(unparsable connection string)";
|
|
}
|
|
}
|
|
}
|