- access_reader.delete_log_ids returns the actual rows deleted (was None). - sql_writer.mark_cleaned flips applied queue rows to 'cleaned' (sets CleanedAt) after their Access log rows are physically removed, so the same IDs are never deleted twice. - sql_writer.purge_cleaned removes 'cleaned' rows older than a retention window (default 24h) so SyncQueue stops growing without bound. - cleanup.cleanup_file marks rows cleaned after a successful delete and returns the real delete count, so the service log reports honest 'cleaned N' instead of a constant. - service.cycle calls purge_cleaned once per pass; config adds cleaned_retention_hours (default 24). - sql/01_sync_queue.sql adds CleanedAt column + IX_SyncQueue_Cleaned idempotently. - tests: unit coverage for mark_cleaned/purge_cleaned/delete_log_ids return count; assert cycle purges each pass.
63 lines
2.3 KiB
Transact-SQL
63 lines
2.3 KiB
Transact-SQL
-- SyncQueue: staging table for the Access -> SQL Server one-way sync.
|
|
-- Idempotent: safe to re-run (table created only if absent; indexes only if absent).
|
|
|
|
IF OBJECT_ID('dbo.SyncQueue', 'U') IS NULL
|
|
BEGIN
|
|
CREATE TABLE dbo.SyncQueue (
|
|
QueueID bigint IDENTITY(1,1) NOT NULL,
|
|
SourceFile nvarchar(255) NOT NULL,
|
|
SourceTable nvarchar(255) NOT NULL,
|
|
SourceLogID bigint NOT NULL,
|
|
TargetSchema nvarchar(128) NOT NULL,
|
|
TargetTable nvarchar(255) NOT NULL,
|
|
RecordID nvarchar(50) NOT NULL,
|
|
OperateType varchar(10) NOT NULL,
|
|
RowData nvarchar(max) NULL,
|
|
Status varchar(10) NOT NULL CONSTRAINT DF_SyncQueue_Status DEFAULT 'pending',
|
|
RetryCount int NOT NULL CONSTRAINT DF_SyncQueue_Retry DEFAULT 0,
|
|
ErrorMsg nvarchar(max) NULL,
|
|
CapturedAt datetime2 NOT NULL CONSTRAINT DF_SyncQueue_Captured DEFAULT sysdatetime(),
|
|
AppliedAt datetime2 NULL,
|
|
CONSTRAINT PK_SyncQueue PRIMARY KEY CLUSTERED (QueueID)
|
|
);
|
|
END
|
|
GO
|
|
|
|
IF NOT EXISTS (SELECT 1 FROM sys.indexes
|
|
WHERE name = 'UX_SyncQueue_Dedup'
|
|
AND object_id = OBJECT_ID('dbo.SyncQueue'))
|
|
BEGIN
|
|
CREATE UNIQUE INDEX UX_SyncQueue_Dedup
|
|
ON dbo.SyncQueue(SourceFile, SourceTable, SourceLogID);
|
|
END
|
|
GO
|
|
|
|
IF NOT EXISTS (SELECT 1 FROM sys.indexes
|
|
WHERE name = 'IX_SyncQueue_Pending'
|
|
AND object_id = OBJECT_ID('dbo.SyncQueue'))
|
|
BEGIN
|
|
CREATE INDEX IX_SyncQueue_Pending
|
|
ON dbo.SyncQueue(Status, TargetSchema, TargetTable);
|
|
END
|
|
GO
|
|
|
|
-- Cleanup bookkeeping: track when a queue row's Access log counterpart has
|
|
-- been physically deleted, so cleanup never re-deletes the same IDs and the
|
|
-- table can be purged to bound its growth.
|
|
IF NOT EXISTS (SELECT 1 FROM sys.columns
|
|
WHERE object_id = OBJECT_ID('dbo.SyncQueue')
|
|
AND name = 'CleanedAt')
|
|
BEGIN
|
|
ALTER TABLE dbo.SyncQueue ADD CleanedAt datetime2 NULL;
|
|
END
|
|
GO
|
|
|
|
IF NOT EXISTS (SELECT 1 FROM sys.indexes
|
|
WHERE name = 'IX_SyncQueue_Cleaned'
|
|
AND object_id = OBJECT_ID('dbo.SyncQueue'))
|
|
BEGIN
|
|
CREATE INDEX IX_SyncQueue_Cleaned
|
|
ON dbo.SyncQueue(Status, CleanedAt);
|
|
END
|
|
GO
|