Fixed unclosed prepared database queries blocking server. Added better error checking and bad request fallbacks to webapp

This commit is contained in:
Daniel Ledda
2020-11-28 09:05:59 +01:00
parent 785e40d0ec
commit 1f2df8b069
3 changed files with 38 additions and 35 deletions

View File

@@ -30,6 +30,10 @@ func writeSnapshotToDb(snapshotSub *SnapshotSubmission) (int64, error) {
queryStr := "INSERT INTO `snapshots` (`temp`, `humidity`, `co2`, `time`, `id`) VALUES (?, ?, ?, ?, NULL);"
query, err := ClimateDb.Prepare(queryStr)
if err != nil {
closeErr := query.Close()
if closeErr != nil {
return -1, fmt.Errorf("couldn't prepare snapshot query: %w. (also failed to close: %s)", err, closeErr.Error())
}
return -1, fmt.Errorf("couldn't prepare snapshot query: %w", err)
}
result, err := query.Exec(

2
webapp/dist/main.js vendored

File diff suppressed because one or more lines are too long

View File

@@ -1,5 +1,4 @@
import Chart from "chart.js/dist/Chart.bundle.min";
import type {ChartPoint} from "chart.js";
import {generateClimateChartConfig} from "./climateChartConfig";
import {config} from "./main";
@@ -53,48 +52,48 @@ class ClimateChart {
throw new Error(`improper HTML element passed, needed type canvas, got ${canvasElement.tagName}`);
}
this.chart = new Chart(ctx, generateClimateChartConfig({}));
try {
const payload = await this.getInitialDataBlob();
this.latestSnapshot = payload.snapshots[0];
this.insertSnapshots(...payload.snapshots);
this.rerender();
setInterval(async () => this.updateFromServer().catch(e => this.logError(e)), 30 * 1000);
this.onLoadedCallback();
}
catch (e) {
new Error(`Server error: ${e}`)
setInterval(this.doUpdateInterval, 30 * 1000);
await this.doUpdateInterval();
this.onLoadedCallback();
}
private async doUpdateInterval() {
await this.updateFromServer().catch(e => this.logError(e));
}
private async getNewSnapshots(): Promise<SnapshotRecords> {
const lastTimeInChart = this.latestSnapshot?.time ?? null;
if (!lastTimeInChart) {
const minutesAsDate = (new Date().getTime() - this.minutesDisplayed * 60000);
const dataEndpoint = `${ this.dataEndpointBase }?since=${ new Date(minutesAsDate).toISOString() }`;
return (await fetch(dataEndpoint)).json();
} else {
const url = `${ this.dataEndpointBase }?since=${ new Date(lastTimeInChart + "+00:00").toISOString() }`;
return (await fetch(url)).json();
}
}
private async getInitialDataBlob(): Promise<SnapshotRecords> {
const minutesAsDate = (new Date().getTime() - this.minutesDisplayed * 60000);
const dataEndpoint = `${ this.dataEndpointBase }?since=${ new Date(minutesAsDate).toISOString() }`;
const payload = await (await fetch(dataEndpoint)).json();
if (payload.snapshots.length < 0) {
throw new Error("Bad response - no snapshots found!");
private async tryGetNewSnapshots(): Promise<SnapshotRecords> {
try {
return this.getNewSnapshots();
} catch (e) {
this.logError(`Server error: ${e}`);
return { snapshots: [] };
}
return payload;
}
private async updateFromServer() {
const lastTimeInChart = this.latestSnapshot.time;
const url = `${ this.dataEndpointBase }?since=${ new Date(this.latestSnapshot.time + "+00:00").toISOString() }`;
try {
const payload: SnapshotRecords = await (await fetch(url)).json();
if (payload.snapshots.length > 0) {
const newLatestTime = new Date(payload.snapshots[0].time).getTime();
if (newLatestTime > new Date(lastTimeInChart).getTime()) {
console.log(payload);
this.removePointsOlderThan(newLatestTime - this.minutesDisplayed * 60000);
this.latestSnapshot = payload.snapshots[0];
this.insertSnapshots(...payload.snapshots);
this.rerender();
}
const payload = await this.tryGetNewSnapshots();
if (payload.snapshots.length > 0) {
const oldLatestTime = new Date(this.latestSnapshot?.time ?? null).getTime();
const newLatestTime = new Date(payload.snapshots[0].time).getTime();
if (newLatestTime > oldLatestTime) {
this.removePointsOlderThan(newLatestTime - this.minutesDisplayed * 60000);
this.latestSnapshot = payload.snapshots[0];
this.insertSnapshots(...payload.snapshots);
this.rerender();
}
}
catch (e) {
this.logError(`Server error: ${e}`);
}
}
private rerender() {