Files
ContentGen_BE/media-worker/Services/DatabaseService.cs
Harun CAN 85c35c73e8
Some checks failed
Backend Deploy 🚀 / build-and-deploy (push) Has been cancelled
main
2026-03-29 12:43:49 +03:00

141 lines
6.1 KiB
C#
Raw Blame History

This file contains ambiguous Unicode characters
This file contains Unicode characters that might be confused with other characters. If you think that this is intentional, you can safely ignore this warning. Use the Escape button to reveal them.
using Microsoft.Extensions.Configuration;
using Microsoft.Extensions.Logging;
using Npgsql;
namespace SaasMediaWorker.Services;
/// <summary>
/// PostgreSQL veritabanı servisi — RenderJob ve Project durumlarını günceller.
/// NestJS Prisma schema'sıyla uyumlu SQL sorguları kullanır.
///
/// Neden doğrudan SQL (ORM yerine)?
/// - C# Worker minimum footprint olmalı (16GB RPi).
/// - Sadece UPDATE sorguları yapılıyor — ORM gereksiz overhead.
/// - Npgsql ARM64'te native çalışır.
/// </summary>
public class DatabaseService
{
private readonly ILogger<DatabaseService> _logger;
private readonly string _connectionString;
public DatabaseService(
ILogger<DatabaseService> logger,
IConfiguration configuration)
{
_logger = logger;
_connectionString = configuration.GetConnectionString("DefaultConnection")
?? throw new InvalidOperationException("DefaultConnection bağlantı dizesi bulunamadı");
}
/// <summary>
/// RenderJob tablosunun durumunu günceller.
/// </summary>
public async Task UpdateRenderJobStatus(
string renderJobId,
string status,
int progress,
string? currentStage,
string? errorMessage = null,
string? errorStack = null,
long? processingTimeMs = null,
string? workerVersion = null,
string? workerHostname = null)
{
await using var conn = new NpgsqlConnection(_connectionString);
await conn.OpenAsync();
var sql = @"
UPDATE ""RenderJob""
SET ""status"" = @status::""RenderJobStatus"",
""progress"" = @progress,
""currentStage"" = CASE WHEN @stage IS NOT NULL THEN @stage::""RenderStage"" ELSE ""currentStage"" END,
""errorMessage"" = COALESCE(@errorMessage, ""errorMessage""),
""errorStack"" = COALESCE(@errorStack, ""errorStack""),
""processingTimeMs"" = COALESCE(@processingTimeMs, ""processingTimeMs""),
""workerVersion"" = COALESCE(@workerVersion, ""workerVersion""),
""workerHostname"" = COALESCE(@workerHostname, ""workerHostname""),
""startedAt"" = CASE WHEN @status = 'PROCESSING' AND ""startedAt"" IS NULL THEN NOW() ELSE ""startedAt"" END,
""completedAt"" = CASE WHEN @status IN ('COMPLETED', 'FAILED') THEN NOW() ELSE ""completedAt"" END,
""lastErrorAt"" = CASE WHEN @status = 'FAILED' THEN NOW() ELSE ""lastErrorAt"" END,
""updatedAt"" = NOW()
WHERE ""id"" = @id";
await using var cmd = new NpgsqlCommand(sql, conn);
cmd.Parameters.AddWithValue("id", renderJobId);
cmd.Parameters.AddWithValue("status", status);
cmd.Parameters.AddWithValue("progress", progress);
cmd.Parameters.AddWithValue("stage", (object?)currentStage ?? DBNull.Value);
cmd.Parameters.AddWithValue("errorMessage", (object?)errorMessage ?? DBNull.Value);
cmd.Parameters.AddWithValue("errorStack", (object?)errorStack ?? DBNull.Value);
cmd.Parameters.AddWithValue("processingTimeMs", (object?)processingTimeMs ?? DBNull.Value);
cmd.Parameters.AddWithValue("workerVersion", (object?)workerVersion ?? DBNull.Value);
cmd.Parameters.AddWithValue("workerHostname", (object?)workerHostname ?? DBNull.Value);
var affected = await cmd.ExecuteNonQueryAsync();
_logger.LogDebug("RenderJob güncellendi: {Id} → {Status} ({Progress}%)", renderJobId, status, progress);
}
/// <summary>
/// Project tablosunun durumunu günceller.
/// </summary>
public async Task UpdateProjectStatus(
string projectId,
string status,
int progress,
string? finalVideoUrl = null,
string? errorMessage = null)
{
await using var conn = new NpgsqlConnection(_connectionString);
await conn.OpenAsync();
var sql = @"
UPDATE ""Project""
SET ""status"" = @status::""ProjectStatus"",
""progress"" = @progress,
""finalVideoUrl"" = COALESCE(@finalVideoUrl, ""finalVideoUrl""),
""errorMessage"" = @errorMessage,
""completedAt"" = CASE WHEN @status = 'COMPLETED' THEN NOW() ELSE ""completedAt"" END,
""updatedAt"" = NOW()
WHERE ""id"" = @id";
await using var cmd = new NpgsqlCommand(sql, conn);
cmd.Parameters.AddWithValue("id", projectId);
cmd.Parameters.AddWithValue("status", status);
cmd.Parameters.AddWithValue("progress", progress);
cmd.Parameters.AddWithValue("finalVideoUrl", (object?)finalVideoUrl ?? DBNull.Value);
cmd.Parameters.AddWithValue("errorMessage", (object?)errorMessage ?? DBNull.Value);
await cmd.ExecuteNonQueryAsync();
_logger.LogDebug("Project güncellendi: {Id} → {Status} ({Progress}%)", projectId, status, progress);
}
/// <summary>
/// Render log kaydı ekler.
/// </summary>
public async Task AddRenderLog(
string renderJobId,
string stage,
string message,
string level = "info",
int? durationMs = null,
string? metadata = null)
{
await using var conn = new NpgsqlConnection(_connectionString);
await conn.OpenAsync();
var sql = @"
INSERT INTO ""RenderLog"" (""id"", ""renderJobId"", ""stage"", ""message"", ""level"", ""durationMs"", ""metadata"", ""createdAt"")
VALUES (gen_random_uuid(), @renderJobId, @stage::""RenderStage"", @message, @level, @durationMs, @metadata::jsonb, NOW())";
await using var cmd = new NpgsqlCommand(sql, conn);
cmd.Parameters.AddWithValue("renderJobId", renderJobId);
cmd.Parameters.AddWithValue("stage", stage);
cmd.Parameters.AddWithValue("message", message);
cmd.Parameters.AddWithValue("level", level);
cmd.Parameters.AddWithValue("durationMs", (object?)durationMs ?? DBNull.Value);
cmd.Parameters.AddWithValue("metadata", (object?)metadata ?? DBNull.Value);
await cmd.ExecuteNonQueryAsync();
}
}