diff --git a/Environment/Service/Data/Database.cs b/Environment/Service/Data/Database.cs index a14d46c..e46e28f 100644 --- a/Environment/Service/Data/Database.cs +++ b/Environment/Service/Data/Database.cs @@ -1,7 +1,7 @@ -using System.Reflection; -using Dapper; +using Dapper; using DbUp; -using Microsoft.Data.SqlClient; +using Npgsql; +using System.Reflection; namespace ChrisKaczor.HomeMonitor.Environment.Service.Data; @@ -9,12 +9,13 @@ public class Database(IConfiguration configuration) { private string GetConnectionString() { - var connectionStringBuilder = new SqlConnectionStringBuilder + var connectionStringBuilder = new NpgsqlConnectionStringBuilder { - DataSource = $"{configuration["Environment:Database:Host"]},{configuration["Environment:Database:Port"]}", - UserID = configuration["Environment:Database:User"], + Host = configuration["Environment:Database:Host"], + Port = configuration.GetValue("Environment:Database:Port"), + Username = configuration["Environment:Database:User"], Password = configuration["Environment:Database:Password"], - InitialCatalog = configuration["Environment:Database:Name"], + Database = configuration["Environment:Database:Name"], TrustServerCertificate = bool.Parse(configuration["Environment:Database:TrustServerCertificate"] ?? "false") }; @@ -25,16 +26,16 @@ public class Database(IConfiguration configuration) { var connectionString = GetConnectionString(); - DbUp.EnsureDatabase.For.SqlDatabase(connectionString); + DbUp.EnsureDatabase.For.PostgresqlDatabase(connectionString); - var upgradeEngine = DeployChanges.To.SqlDatabase(connectionString).WithScriptsEmbeddedInAssembly(Assembly.GetExecutingAssembly(), s => s.Contains(".Schema.")).LogToConsole().Build(); + var upgradeEngine = DeployChanges.To.PostgresqlDatabase(connectionString).WithScriptsEmbeddedInAssembly(Assembly.GetExecutingAssembly(), s => s.Contains(".Schema.")).LogToConsole().Build(); upgradeEngine.PerformUpgrade(); } - private SqlConnection CreateConnection() + private NpgsqlConnection CreateConnection() { - var connection = new SqlConnection(GetConnectionString()); + var connection = new NpgsqlConnection(GetConnectionString()); connection.Open(); return connection; diff --git a/Environment/Service/Data/Queries/CreateReading.sql b/Environment/Service/Data/Queries/CreateReading.sql index 06ecd86..8591f36 100644 --- a/Environment/Service/Data/Queries/CreateReading.sql +++ b/Environment/Service/Data/Queries/CreateReading.sql @@ -1,25 +1,30 @@ -BEGIN TRANSACTION - -INSERT Reading - (Timestamp, Name, Model, Temperature, Pressure, Humidity, Luminance, GasResistance, ColorTemperature, AirQualityIndex) -SELECT - @Timestamp, - @Name, - @Model, - @Temperature, - @Pressure, - @Humidity, - @Luminance, - @GasResistance, - @ColorTemperature, - @AirQualityIndex -WHERE NOT EXISTS - ( - SELECT - 1 - FROM - Reading WITH (UPDLOCK, SERIALIZABLE) - WHERE Timestamp = @Timestamp AND Name = @Name AND Model = @Model - ) - -COMMIT TRANSACTION \ No newline at end of file +INSERT INTO + reading + ( + time, + name, + model, + temperature, + pressure, + humidity, + luminance, + gas_resistance, + color_temperature, + air_quality_index + ) +VALUES + ( + @Timestamp, + @Name, + @Model, + @Temperature, + @Pressure, + @Humidity, + @Luminance, + @GasResistance, + @ColorTemperature, + @AirQualityIndex + ) +ON CONFLICT + ON CONSTRAINT reading_pk + DO NOTHING \ No newline at end of file diff --git a/Environment/Service/Data/Schema/1-Initial Schema.sql b/Environment/Service/Data/Schema/1-Initial Schema.sql index a24e750..ea39f30 100644 --- a/Environment/Service/Data/Schema/1-Initial Schema.sql +++ b/Environment/Service/Data/Schema/1-Initial Schema.sql @@ -1,14 +1,17 @@ -CREATE TABLE Reading -( - Timestamp datetimeoffset NOT NULL, - Name nvarchar(50) NOT NULL, - Model nvarchar(50) NOT NULL, - Temperature decimal(5, 2) NOT NULL, - Pressure decimal(6, 2) NOT NULL, - Humidity decimal(5, 2) NOT NULL, - Luminance int NOT NULL, - GasResistance int NOT NULL, - ColorTemperature int NOT NULL, - AirQualityIndex decimal(4, 1) NOT NULL, - CONSTRAINT reading_pk PRIMARY KEY (Timestamp, Name, Model) -); +CREATE TABLE + reading ( + time timestamptz NOT NULL, + name text NOT NULL, + model text NOT NULL, + temperature DECIMAL NOT NULL, + pressure DECIMAL NOT NULL, + humidity DECIMAL NOT NULL, + luminance INT NOT NULL, + gas_resistance INT NOT NULL, + color_temperature INT NOT NULL, + air_quality_index DECIMAL NOT NULL, + CONSTRAINT reading_pk PRIMARY KEY (time, name, model) + ); + +SELECT + create_hypertable('reading', by_range('time')); \ No newline at end of file diff --git a/Environment/Service/MessageHandler.cs b/Environment/Service/MessageHandler.cs index d3cb85e..0f6c3b7 100644 --- a/Environment/Service/MessageHandler.cs +++ b/Environment/Service/MessageHandler.cs @@ -14,7 +14,7 @@ public class MessageHandler : IHostedService private readonly MqttFactory _mqttFactory; private readonly string _topic; - private readonly HubConnection _hubConnection; + private readonly HubConnection? _hubConnection; public MessageHandler(IConfiguration configuration, Database database) { @@ -33,12 +33,16 @@ public class MessageHandler : IHostedService _mqttClient.ApplicationMessageReceivedAsync += OnApplicationMessageReceivedAsync; - _hubConnection = new HubConnectionBuilder().WithUrl(configuration["Environment:Hub:Url"] ?? string.Empty).Build(); + var hubUrl = configuration["Environment:Hub:Url"]; + + if (!string.IsNullOrEmpty(hubUrl)) + _hubConnection = new HubConnectionBuilder().WithUrl(hubUrl).Build(); } public async Task StartAsync(CancellationToken cancellationToken) { - await _hubConnection.StartAsync(cancellationToken); + if (_hubConnection != null) + await _hubConnection.StartAsync(cancellationToken); var mqttClientOptions = new MqttClientOptionsBuilder().WithTcpServer(_configuration["Mqtt:Server"]).Build(); await _mqttClient.ConnectAsync(mqttClientOptions, cancellationToken); @@ -51,7 +55,8 @@ public class MessageHandler : IHostedService { await _mqttClient.DisconnectAsync(new MqttClientDisconnectOptionsBuilder().Build(), cancellationToken); - await _hubConnection.StopAsync(cancellationToken); + if (_hubConnection != null) + await _hubConnection.StopAsync(cancellationToken); } private async Task OnApplicationMessageReceivedAsync(MqttApplicationMessageReceivedEventArgs arg) @@ -75,6 +80,9 @@ public class MessageHandler : IHostedService { try { + if (_hubConnection == null) + return; + if (_hubConnection.State == HubConnectionState.Disconnected) await _hubConnection.StartAsync(); diff --git a/Environment/Service/Service.csproj b/Environment/Service/Service.csproj index 61155af..b729ca1 100644 --- a/Environment/Service/Service.csproj +++ b/Environment/Service/Service.csproj @@ -20,9 +20,9 @@ - + - + diff --git a/Environment/Service/appsettings.json b/Environment/Service/appsettings.json index 3bf5e22..be22a58 100644 --- a/Environment/Service/appsettings.json +++ b/Environment/Service/appsettings.json @@ -15,9 +15,9 @@ "Host": "", "User": "", "Password": "", - "Name": "Environment", + "Name": "environment", "TrustServerCertificate": true, - "Port": 1435 + "Port": 5432 }, "Hub": { "Url": "http://hub-server/environment" diff --git a/Environment/Service/deploy/manifest.yaml b/Environment/Service/deploy/manifest.yaml index 04bf125..b1ec028 100644 --- a/Environment/Service/deploy/manifest.yaml +++ b/Environment/Service/deploy/manifest.yaml @@ -19,27 +19,31 @@ spec: spec: containers: - name: environment-database - image: mcr.microsoft.com/mssql/server - terminationMessagePath: "/dev/termination-log" - terminationMessagePolicy: File + image: timescale/timescaledb:latest-pg16 imagePullPolicy: IfNotPresent env: - - name: SA_PASSWORD + - name: POSTGRES_USER + valueFrom: + secretKeyRef: + name: environment-database-credentials + key: username + - name: POSTGRES_PASSWORD valueFrom: secretKeyRef: name: environment-database-credentials key: password - - name: ACCEPT_EULA - value: "Y" - - name: MSSQL_PID - value: Express - - name: MSSQL_TCP_PORT - value: "1435" - - name: TZ - value: America/New_York + - name: POSTGRES_DB + value: environment volumeMounts: - name: data - mountPath: /var/opt/mssql + mountPath: /var/lib/postgresql/data + resources: + limits: + cpu: 1000m + memory: 1Gi + requests: + cpu: 500m + memory: 512Mi restartPolicy: Always terminationGracePeriodSeconds: 30 dnsPolicy: ClusterFirst @@ -63,7 +67,7 @@ metadata: spec: ports: - name: client - port: 1435 + port: 5432 selector: app: environment-database type: LoadBalancer @@ -108,6 +112,13 @@ spec: key: password - name: Environment__Hub__Url value: http://hub-service/environment + resources: + limits: + cpu: 1 + memory: 1Gi + requests: + cpu: 500m + memory: 512Mi restartPolicy: Always terminationGracePeriodSeconds: 30 dnsPolicy: ClusterFirst