Skip to content

Commit 97d3e78

Browse files
refactor: Remove drop_created_before alter_job workaround
TimescaleDB 2.26.3 (timescale/timescaledb#9577) fixed the policy_retention_check bug that caused alter_job to fail on drop_created_before retention policies. The workaround in RetentionPolicyOperationGenerator that short-circuited BuildAlterJobClauses for these policies is no longer needed.
1 parent e97729a commit 97d3e78

6 files changed

Lines changed: 326 additions & 42 deletions

File tree

docs/data-annotations/retention-policies.md

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -54,7 +54,7 @@ public class ApiRequestLog
5454
}
5555
```
5656

57-
> :warning: **Note:** Due to a known bug in TimescaleDB ([#9446](https://github.com/timescale/timescaledb/issues/9446)), `alter_job` fails when used with `DropCreatedBefore` policies. The library works around this by skipping the `alter_job` call for `DropCreatedBefore` policies. As a result, job scheduling parameters (`ScheduleInterval`, `MaxRuntime`, `MaxRetries`, `RetryPeriod`) are accepted by the API but have no effect at the database level when `DropCreatedBefore` is used.
57+
> :warning: **Note:** Customizing job scheduling parameters (`ScheduleInterval`, `MaxRuntime`, `MaxRetries`, `RetryPeriod`) on a `DropCreatedBefore` policy requires **TimescaleDB 2.26.3 or later**. Earlier versions contain a bug in `alter_job` that prevents these settings from being applied for `drop_created_before` policies. Policies using `DropAfter` are not affected and work on all supported TimescaleDB versions.
5858
5959
## Complete Example
6060

docs/fluent-api/retention-policies.md

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -59,7 +59,7 @@ public class ApiRequestLogConfiguration : IEntityTypeConfiguration<ApiRequestLog
5959
}
6060
```
6161

62-
> :warning: **Note:** Due to a known bug in TimescaleDB ([#9446](https://github.com/timescale/timescaledb/issues/9446)), `alter_job` fails when used with `drop_created_before` policies. The library works around this by skipping the `alter_job` call for `drop_created_before` policies. As a result, job scheduling parameters (`scheduleInterval`, `maxRuntime`, `maxRetries`, `retryPeriod`) are accepted by the API but have no effect at the database level when `dropCreatedBefore` is used.
62+
> :warning: **Note:** Customizing job scheduling parameters (`scheduleInterval`, `maxRuntime`, `maxRetries`, `retryPeriod`) on a `dropCreatedBefore` policy requires **TimescaleDB 2.26.3 or later**. Earlier versions contain a bug in `alter_job` that prevents these settings from being applied for `drop_created_before` policies. Policies using `dropAfter` are not affected and work on all supported TimescaleDB versions.
6363
6464
## Complete Example
6565

src/Eftdb/Generators/RetentionPolicyOperationGenerator.cs

Lines changed: 0 additions & 20 deletions
Original file line numberDiff line numberDiff line change
@@ -96,16 +96,6 @@ private static List<string> BuildAlterJobClauses(AddRetentionPolicyOperation ope
9696
{
9797
List<string> clauses = [];
9898

99-
// alter_job fails for drop_created_before retention policies.
100-
// TimescaleDB's policy_retention_check expects drop_after in the job config JSONB
101-
// but finds drop_created_before instead. Workaround: avoid alter_job for
102-
// drop_created_before policies, or recreate the policy entirely.
103-
// TODO: Remove this when a fix has been applied to TimescaleDB.
104-
if (!string.IsNullOrEmpty(operation.DropCreatedBefore))
105-
{
106-
return clauses;
107-
}
108-
10999
if (!string.IsNullOrWhiteSpace(operation.ScheduleInterval))
110100
clauses.Add($"schedule_interval => INTERVAL '{operation.ScheduleInterval}'");
111101

@@ -125,16 +115,6 @@ private static List<string> BuildAlterJobClauses(AlterRetentionPolicyOperation o
125115
{
126116
List<string> clauses = [];
127117

128-
// alter_job fails for drop_created_before retention policies.
129-
// TimescaleDB's policy_retention_check expects drop_after in the job config JSONB
130-
// but finds drop_created_before instead. Workaround: avoid alter_job for
131-
// drop_created_before policies, or recreate the policy entirely.
132-
// TODO: Remove this when a fix has been applied to TimescaleDB.
133-
if (!string.IsNullOrEmpty(operation.DropCreatedBefore))
134-
{
135-
return clauses;
136-
}
137-
138118
if (!string.IsNullOrWhiteSpace(operation.ScheduleInterval) && operation.ScheduleInterval != operation.OldScheduleInterval)
139119
clauses.Add($"schedule_interval => INTERVAL '{operation.ScheduleInterval}'");
140120

tests/Eftdb.Tests/Generators/RetentionPolicyOperationGeneratorTests.cs

Lines changed: 27 additions & 18 deletions
Original file line numberDiff line numberDiff line change
@@ -47,10 +47,10 @@ public void Generate_Add_DropAfter_with_minimal_config_creates_only_add_policy_s
4747

4848
#endregion
4949

50-
#region Generate_Add_DropCreatedBefore_creates_add_policy_without_alter_job
50+
#region Generate_Add_DropCreatedBefore_with_job_settings_creates_add_and_alter_job_sql
5151

5252
[Fact]
53-
public void Generate_Add_DropCreatedBefore_creates_add_policy_without_alter_job()
53+
public void Generate_Add_DropCreatedBefore_with_job_settings_creates_add_and_alter_job_sql()
5454
{
5555
// Arrange
5656
AddRetentionPolicyOperation operation = new()
@@ -62,10 +62,11 @@ public void Generate_Add_DropCreatedBefore_creates_add_policy_without_alter_job(
6262
MaxRetries = 5
6363
};
6464

65-
// DropCreatedBefore policies must not emit alter_job due to TimescaleDB bug #9446.
66-
// Job settings are intentionally ignored.
6765
string expected = @".Sql(@""
6866
SELECT add_retention_policy('public.""""TestTable""""', drop_created_before => INTERVAL '30 days');
67+
SELECT alter_job(job_id, schedule_interval => INTERVAL '1 day', max_retries => 5)
68+
FROM timescaledb_information.jobs
69+
WHERE proc_name = 'policy_retention' AND hypertable_schema = 'public' AND hypertable_name = 'TestTable';
6970
"")";
7071

7172
// Act
@@ -138,10 +139,10 @@ FROM timescaledb_information.jobs
138139

139140
#endregion
140141

141-
#region Generate_Add_DropCreatedBefore_with_job_settings_still_omits_alter_job
142+
#region Generate_Add_DropCreatedBefore_with_all_job_settings_creates_add_and_alter_job_sql
142143

143144
[Fact]
144-
public void Generate_Add_DropCreatedBefore_with_job_settings_still_omits_alter_job()
145+
public void Generate_Add_DropCreatedBefore_with_all_job_settings_creates_add_and_alter_job_sql()
145146
{
146147
// Arrange
147148
AddRetentionPolicyOperation operation = new()
@@ -155,10 +156,11 @@ public void Generate_Add_DropCreatedBefore_with_job_settings_still_omits_alter_j
155156
RetryPeriod = "10 minutes"
156157
};
157158

158-
// Even with all job settings specified, alter_job is omitted for DropCreatedBefore
159-
// due to TimescaleDB bug #9446 workaround.
160159
string expected = @".Sql(@""
161160
SELECT add_retention_policy('public.""""TestTable""""', drop_created_before => INTERVAL '30 days');
161+
SELECT alter_job(job_id, schedule_interval => INTERVAL '2 days', max_runtime => INTERVAL '1 hour', max_retries => 5, retry_period => INTERVAL '10 minutes')
162+
FROM timescaledb_information.jobs
163+
WHERE proc_name = 'policy_retention' AND hypertable_schema = 'public' AND hypertable_name = 'TestTable';
162164
"")";
163165

164166
// Act
@@ -240,10 +242,10 @@ FROM timescaledb_information.jobs
240242

241243
#endregion
242244

243-
#region Generate_Alter_changed_to_DropCreatedBefore_creates_remove_and_add_without_alter_job
245+
#region Generate_Alter_changed_to_DropCreatedBefore_creates_remove_add_and_alter_job_sql
244246

245247
[Fact]
246-
public void Generate_Alter_changed_to_DropCreatedBefore_creates_remove_and_add_without_alter_job()
248+
public void Generate_Alter_changed_to_DropCreatedBefore_creates_remove_add_and_alter_job_sql()
247249
{
248250
// Arrange
249251
AlterRetentionPolicyOperation operation = new()
@@ -258,11 +260,13 @@ public void Generate_Alter_changed_to_DropCreatedBefore_creates_remove_and_add_w
258260
OldScheduleInterval = "1 day"
259261
};
260262

261-
// During Alter recreation, alter_job is still emitted to reapply existing job settings.
262-
// The DropCreatedBefore workaround only applies to the Add path.
263+
// During recreation, alter_job is emitted to reapply the final-state job settings
263264
string expected = @".Sql(@""
264265
SELECT remove_retention_policy('public.""""TestTable""""', if_exists => true);
265266
SELECT add_retention_policy('public.""""TestTable""""', drop_created_before => INTERVAL '30 days');
267+
SELECT alter_job(job_id, schedule_interval => INTERVAL '1 day')
268+
FROM timescaledb_information.jobs
269+
WHERE proc_name = 'policy_retention' AND hypertable_schema = 'public' AND hypertable_name = 'TestTable';
266270
"")";
267271

268272
// Act
@@ -400,10 +404,10 @@ FROM timescaledb_information.jobs
400404

401405
#endregion
402406

403-
#region Generate_Alter_DropCreatedBefore_job_settings_change_skips_alter_job
407+
#region Generate_Alter_DropCreatedBefore_only_job_settings_change_emits_alter_job
404408

405409
[Fact]
406-
public void Generate_Alter_DropCreatedBefore_job_settings_change_skips_alter_job()
410+
public void Generate_Alter_DropCreatedBefore_only_job_settings_change_emits_alter_job()
407411
{
408412
// Arrange
409413
AlterRetentionPolicyOperation operation = new()
@@ -420,12 +424,17 @@ public void Generate_Alter_DropCreatedBefore_job_settings_change_skips_alter_job
420424
OldScheduleInterval = "1 day"
421425
};
422426

423-
// No recreation needed, but alter_job is skipped for DropCreatedBefore due to TimescaleDB bug #9446.
424-
RetentionPolicyOperationGenerator generator = new(true);
425-
List<string> result = generator.Generate(operation);
427+
string expected = @".Sql(@""
428+
SELECT alter_job(job_id, schedule_interval => INTERVAL '2 days')
429+
FROM timescaledb_information.jobs
430+
WHERE proc_name = 'policy_retention' AND hypertable_schema = 'public' AND hypertable_name = 'TestTable';
431+
"")";
432+
433+
// Act
434+
string result = GetGeneratedCode(operation);
426435

427436
// Assert
428-
Assert.Empty(result);
437+
Assert.Equal(SqlHelper.NormalizeSql(expected), SqlHelper.NormalizeSql(result));
429438
}
430439

431440
#endregion

0 commit comments

Comments
 (0)