Skip to content
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
3 changes: 3 additions & 0 deletions .devcontainer/docker-compose.yml
Original file line number Diff line number Diff line change
Expand Up @@ -12,5 +12,8 @@ services:
POSTGRES_USER: trax
POSTGRES_PASSWORD: trax123
POSTGRES_DB: trax
POSTGRES_MULTIPLE_DATABASES: trax_scheduler_tests,trax_data_tests
ports:
- "5432:5432"
volumes:
- ../init-databases.sh:/docker-entrypoint-initdb.d/init-databases.sh
3 changes: 3 additions & 0 deletions docker-compose.yml
Original file line number Diff line number Diff line change
Expand Up @@ -8,8 +8,11 @@ services:
POSTGRES_USER: trax
POSTGRES_PASSWORD: trax123
POSTGRES_DB: trax
POSTGRES_MULTIPLE_DATABASES: trax_scheduler_tests,trax_data_tests
tty: true
ports:
- "5432:5432"
networks:
- default
volumes:
- ./init-databases.sh:/docker-entrypoint-initdb.d/init-databases.sh
19 changes: 19 additions & 0 deletions init-databases.sh
Original file line number Diff line number Diff line change
@@ -0,0 +1,19 @@
#!/bin/bash
# Creates additional databases listed in POSTGRES_MULTIPLE_DATABASES.
# Mounted into /docker-entrypoint-initdb.d/ so PostgreSQL runs it on first init.
# Each database is owned by POSTGRES_USER.

set -e
set -u

if [ -z "${POSTGRES_MULTIPLE_DATABASES:-}" ]; then
exit 0
fi

for db in $(echo "$POSTGRES_MULTIPLE_DATABASES" | tr ',' ' '); do
echo "Creating database: $db"
psql -v ON_ERROR_STOP=1 --username "$POSTGRES_USER" <<-EOSQL
CREATE DATABASE "$db";
GRANT ALL PRIVILEGES ON DATABASE "$db" TO "$POSTGRES_USER";
EOSQL
done
Original file line number Diff line number Diff line change
Expand Up @@ -47,6 +47,7 @@ public static ModelBuilder AddPostgresEnums(this ModelBuilder modelBuilder)
modelBuilder.HasPostgresEnum<ScheduleType>(schema: "trax");
modelBuilder.HasPostgresEnum<DeadLetterStatus>(schema: "trax");
modelBuilder.HasPostgresEnum<WorkQueueStatus>(schema: "trax");
modelBuilder.HasPostgresEnum<MisfirePolicy>(schema: "trax");

return modelBuilder;
}
Expand Down Expand Up @@ -75,6 +76,7 @@ public static NpgsqlDataSource BuildDataSource(string connectionString)
npgsqlDataSourceBuilder.MapEnum<ScheduleType>("trax.schedule_type");
npgsqlDataSourceBuilder.MapEnum<DeadLetterStatus>("trax.dead_letter_status");
npgsqlDataSourceBuilder.MapEnum<WorkQueueStatus>("trax.work_queue_status");
npgsqlDataSourceBuilder.MapEnum<MisfirePolicy>("trax.misfire_policy");

return npgsqlDataSourceBuilder.Build();
}
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -87,6 +87,7 @@ string connectionString
o.MapEnum<ScheduleType>("schedule_type", "trax");
o.MapEnum<DeadLetterStatus>("dead_letter_status", "trax");
o.MapEnum<WorkQueueStatus>("work_queue_status", "trax");
o.MapEnum<MisfirePolicy>("misfire_policy", "trax");
}
)
.UseLoggerFactory(new NullLoggerFactory())
Expand Down
Original file line number Diff line number Diff line change
@@ -0,0 +1,7 @@
CREATE TYPE trax.misfire_policy AS ENUM ('fire_once_now', 'do_nothing');

ALTER TABLE trax.manifest
ADD COLUMN misfire_policy trax.misfire_policy NOT NULL DEFAULT 'fire_once_now';

ALTER TABLE trax.manifest
ADD COLUMN misfire_threshold_seconds integer;
25 changes: 25 additions & 0 deletions src/Trax.Effect/Enums/MisfirePolicy.cs
Original file line number Diff line number Diff line change
@@ -0,0 +1,25 @@
namespace Trax.Effect.Enums;

/// <summary>
/// Defines how the scheduler handles missed/overdue runs for a manifest.
/// </summary>
/// <remarks>
/// When the scheduler is down or a manifest's scheduled time passes without execution,
/// the misfire policy determines behavior upon recovery. The policy is evaluated in
/// conjunction with the misfire threshold — if the overdue duration is within the threshold,
/// the job fires normally regardless of policy.
/// </remarks>
public enum MisfirePolicy
{
/// <summary>
/// If overdue, fire once immediately. This is the default behavior.
/// </summary>
FireOnceNow = 0,

/// <summary>
/// If overdue beyond the misfire threshold, skip and wait for the next natural
/// occurrence. For interval-based schedules, the scheduler advances to the most
/// recent interval boundary and checks whether we are within threshold of it.
/// </summary>
DoNothing = 1,
}
10 changes: 10 additions & 0 deletions src/Trax.Effect/Models/Manifest/DTOs/CreateManifest.cs
Original file line number Diff line number Diff line change
Expand Up @@ -60,5 +60,15 @@ public class CreateManifest
/// </summary>
public int Priority { get; set; }

/// <summary>
/// Misfire policy for missed/overdue runs. Defaults to FireOnceNow.
/// </summary>
public MisfirePolicy MisfirePolicy { get; set; } = MisfirePolicy.FireOnceNow;

/// <summary>
/// Misfire threshold in seconds. Null uses the global default.
/// </summary>
public int? MisfireThresholdSeconds { get; set; }

#endregion
}
23 changes: 23 additions & 0 deletions src/Trax.Effect/Models/Manifest/Manifest.cs
Original file line number Diff line number Diff line change
Expand Up @@ -152,6 +152,27 @@ public class Manifest : IModel
[Column("priority")]
public int Priority { get; set; }

/// <summary>
/// Gets or sets the misfire policy for this manifest.
/// </summary>
/// <remarks>
/// Determines behavior when a scheduled run is missed (e.g., scheduler was down).
/// Only applies to Cron and Interval schedule types.
/// </remarks>
[Column("misfire_policy")]
public MisfirePolicy MisfirePolicy { get; set; } = MisfirePolicy.FireOnceNow;

/// <summary>
/// Gets or sets the misfire threshold in seconds for this manifest.
/// </summary>
/// <remarks>
/// Defines the grace period for misfire detection. If a manifest is overdue by less than
/// this threshold, it fires normally regardless of <see cref="MisfirePolicy"/>.
/// Null means use the global default from SchedulerConfiguration.DefaultMisfireThreshold.
/// </remarks>
[Column("misfire_threshold_seconds")]
public int? MisfireThresholdSeconds { get; set; }

#endregion

#endregion
Expand Down Expand Up @@ -212,6 +233,8 @@ public static Manifest Create(CreateManifest manifest)
TimeoutSeconds = manifest.TimeoutSeconds,
DependsOnManifestId = manifest.DependsOnManifestId,
Priority = manifest.Priority,
MisfirePolicy = manifest.MisfirePolicy,
MisfireThresholdSeconds = manifest.MisfireThresholdSeconds,
};

if (manifest.Properties != null)
Expand Down
Loading