fix: stop AddAPICount from throwing on missing DateCreated column

The INSERT named a DateCreated column that DailyAPICount (Date, APICount)
never had, so every call threw "no such column: DateCreated" into an
empty catch block. Today's row was never created and the tally sat idle
since 2026-04-13. Drop the column from the INSERT, and report the three
silent failure points (insert error, missing row after insert, update
matching zero rows) instead of swallowing them.
This commit is contained in:
jim
2026-07-29 16:26:08 -05:00
parent eded5271ea
commit 60912c882d
+41 -5
View File
@@ -80,6 +80,10 @@ namespace URLNotesGrabberCORE
private static SQLiteConnection? _importConnection; private static SQLiteConnection? _importConnection;
private static HashSet<string>? _importBlogCache; private static HashSet<string>? _importBlogCache;
private static readonly object _importSessionLock = new object(); private static readonly object _importSessionLock = new object();
// AddAPICount/UpdateAPICount run once per API call. A schema-level failure there repeats
// identically every time, so log each distinct message once instead of per call.
private static readonly HashSet<string> _apiCountFailuresLogged = new HashSet<string>();
private static readonly object _apiCountFailureLock = new object();
static DataAccess() static DataAccess()
{ {
@@ -566,21 +570,40 @@ namespace URLNotesGrabberCORE
// Use INSERT OR IGNORE to avoid UNIQUE constraint errors when the date row already exists. // Use INSERT OR IGNORE to avoid UNIQUE constraint errors when the date row already exists.
// Also explicitly initialize APICount to 0 in case the table has no default. // Also explicitly initialize APICount to 0 in case the table has no default.
string sql = "INSERT OR IGNORE INTO DailyAPICount (Date, APICount, DateCreated) values(@date, 0, @DateCreated)"; //
// DailyAPICount is (Date TEXT PK, APICount INTEGER) — the crawler never creates or
// migrates this table, and no code reads a creation timestamp off it, so the insert
// names only those two columns. Naming a DateCreated column here used to throw
// "no such column: DateCreated" into a silent catch, which meant the day's row was
// never created and the tally sat at 0 for months.
string sql = "INSERT OR IGNORE INTO DailyAPICount (Date, APICount) values(@date, 0)";
using (SQLiteCommand command = new SQLiteCommand(sql, connection)) using (SQLiteCommand command = new SQLiteCommand(sql, connection))
{ {
command.Parameters.AddWithValue("@date", DateTime.Today.ToShortDateString()); command.Parameters.AddWithValue("@date", DateTime.Today.ToShortDateString());
command.Parameters.AddWithValue("@DateCreated", DateTime.Now.ToString("yyyy-MM-dd HH:mm:ss"));
command.ExecuteNonQuery(); command.ExecuteNonQuery();
} }
} }
catch (Exception ex) catch (Exception ex)
{ {
// Breakpoint here // Breakpoint here
//Console.WriteLine(ex.Message); ReportAPICountFailure($"Error creating the row for {DateTime.Today.ToShortDateString()}: {ex.Message}");
} }
} }
// Bookkeeping writes that fail identically on every API call would flood the console, but
// swallowing them entirely is what hid the DateCreated bug. Log each distinct message once.
// Messages embed today's date, so a date rollover reports afresh.
private static void ReportAPICountFailure(string message)
{
lock (_apiCountFailureLock)
{
if (!_apiCountFailuresLogged.Add(message))
return;
}
Console.WriteLine($"[DailyAPICount] {message}");
}
public static bool AddNote(string rootBlogName, string noteBlogName, long postID, long timestamp, string type, string? DBPath = null) public static bool AddNote(string rootBlogName, string noteBlogName, long postID, long timestamp, string type, string? DBPath = null)
{ {
DBPath ??= GetDefaultDbPath(); DBPath ??= GetDefaultDbPath();
@@ -993,7 +1016,9 @@ namespace URLNotesGrabberCORE
using SQLiteConnection connection = new SQLiteConnection("Data Source=" + DBPath); using SQLiteConnection connection = new SQLiteConnection("Data Source=" + DBPath);
int count = 0; int count = 0;
try { AddAPICount(); } catch { } // AddAPICount reports its own failures; this guard only stops a connection-level
// problem from taking down the read below.
try { AddAPICount(); } catch (Exception ex) { ReportAPICountFailure($"AddAPICount failed: {ex.Message}"); }
try try
{ {
@@ -1001,6 +1026,7 @@ namespace URLNotesGrabberCORE
string sql = "SELECT APICount FROM DailyAPICount WHERE [Date] = @date"; string sql = "SELECT APICount FROM DailyAPICount WHERE [Date] = @date";
bool rowFound = false;
using (SQLiteCommand command = new SQLiteCommand(sql, connection)) using (SQLiteCommand command = new SQLiteCommand(sql, connection))
{ {
command.Parameters.AddWithValue("@date", DateTime.Today.ToShortDateString()); command.Parameters.AddWithValue("@date", DateTime.Today.ToShortDateString());
@@ -1008,10 +1034,16 @@ namespace URLNotesGrabberCORE
{ {
while (reader.Read()) while (reader.Read())
{ {
rowFound = true;
count = reader.GetInt32(0); // Assuming Id is the first column count = reader.GetInt32(0); // Assuming Id is the first column
} }
} }
} }
// A missing row means AddAPICount did not take. Returning a silent 0 here is what
// made the tally look merely idle rather than broken.
if (!rowFound)
ReportAPICountFailure($"No row for {DateTime.Today.ToShortDateString()} after AddAPICount - reported count of 0 is not a real tally.");
} }
catch (Exception ex) catch (Exception ex)
{ {
@@ -1654,7 +1686,11 @@ namespace URLNotesGrabberCORE
{ {
command.Parameters.AddWithValue("@APICount", APICount); command.Parameters.AddWithValue("@APICount", APICount);
command.Parameters.AddWithValue("@date", DateTime.Today.ToShortDateString()); command.Parameters.AddWithValue("@date", DateTime.Today.ToShortDateString());
command.ExecuteNonQuery();
// No row for today means this UPDATE matched nothing and the increment was
// thrown away, while the value returned below still looks like a real count.
if (command.ExecuteNonQuery() == 0)
ReportAPICountFailure($"UPDATE matched no row for {DateTime.Today.ToShortDateString()} - the count of {APICount} was not persisted.");
} }
} }
catch (Exception ex) catch (Exception ex)