diff --git a/src/Common/TeamUp.Common.Infrastructure/Processing/Inbox/InboxConsumer.cs b/src/Common/TeamUp.Common.Infrastructure/Processing/Inbox/InboxConsumer.cs index b28e905..a7c0e00 100644 --- a/src/Common/TeamUp.Common.Infrastructure/Processing/Inbox/InboxConsumer.cs +++ b/src/Common/TeamUp.Common.Infrastructure/Processing/Inbox/InboxConsumer.cs @@ -44,7 +44,7 @@ public InboxConsumer(IServiceProvider serviceProvider, IDateTimeProvider dateTim } } - internal async Task DispatchEventAsync(InboxMessage message, CancellationToken ct = default) + private async Task TryDispatchEventAsync(InboxMessage message, CancellationToken ct = default) { var integrationEventHandlerType = ResolveType(message); if (integrationEventHandlerType is null) @@ -102,11 +102,32 @@ public InboxConsumer(IServiceProvider serviceProvider, IDateTimeProvider dateTim } } - internal static Task> GetInboxAsync(DbContext dbContext, CancellationToken ct) + internal async Task DispatchEventAsync(InboxMessage message, CancellationToken ct = default) + { + var result = await TryDispatchEventAsync(message, ct); + + if (result is null) + { + message.FailCount++; + message.NextProcessingUtc = message.FailCount switch + { + < 5 => _dateTimeProvider.UtcNow, + < 10 => _dateTimeProvider.UtcNow.AddMinutes(message.FailCount - 10), + _ => _dateTimeProvider.UtcNow.AddMinutes(message.FailCount) + }; + } + + return result; + } + + internal Task> GetInboxAsync(DbContext dbContext, CancellationToken ct) { return dbContext .Set() - .Where(msg => msg.ProcessedUtc == null) + .Where(msg => + msg.ProcessedUtc == null && //unprocessed + msg.FailCount != -1 && //not marked for skipping + msg.NextProcessingUtc < _dateTimeProvider.UtcNow) //is scheduled for processing .OrderBy(msg => msg.CreatedUtc) .Take(20) .ToListAsync(ct); diff --git a/src/Common/TeamUp.Common.Infrastructure/Processing/Inbox/InboxMessage.cs b/src/Common/TeamUp.Common.Infrastructure/Processing/Inbox/InboxMessage.cs index 4c7ddc4..ac86bb4 100644 --- a/src/Common/TeamUp.Common.Infrastructure/Processing/Inbox/InboxMessage.cs +++ b/src/Common/TeamUp.Common.Infrastructure/Processing/Inbox/InboxMessage.cs @@ -9,4 +9,6 @@ internal sealed record InboxMessage public required string Data { get; init; } public DateTime? ProcessedUtc { get; set; } = null; public string? Error { get; set; } = null; + public int FailCount { get; set; } = 0; + public DateTime? NextProcessingUtc { get; set; } = null; } diff --git a/src/Common/TeamUp.Common.Infrastructure/Processing/Inbox/InboxProducer.cs b/src/Common/TeamUp.Common.Infrastructure/Processing/Inbox/InboxProducer.cs index bf889e0..04e8c12 100644 --- a/src/Common/TeamUp.Common.Infrastructure/Processing/Inbox/InboxProducer.cs +++ b/src/Common/TeamUp.Common.Infrastructure/Processing/Inbox/InboxProducer.cs @@ -45,7 +45,8 @@ public Task ProduceEventAsync(TEvent integrati CreatedUtc = _dateTimeProvider.UtcNow, Assembly = type.Assembly.GetName().Name!, Type = type.FullName!, - Data = JsonSerializer.Serialize(integrationEvent, JsonSerializerOptions) + Data = JsonSerializer.Serialize(integrationEvent, JsonSerializerOptions), + NextProcessingUtc = _dateTimeProvider.UtcNow }; _dbContext.Set().Add(message); diff --git a/src/Modules/Notifications/TeamUp.Notifications.Infrastructure/Persistence/Migrations/20240506223822_InboxStarvation.Designer.cs b/src/Modules/Notifications/TeamUp.Notifications.Infrastructure/Persistence/Migrations/20240506223822_InboxStarvation.Designer.cs new file mode 100644 index 0000000..9fdae95 --- /dev/null +++ b/src/Modules/Notifications/TeamUp.Notifications.Infrastructure/Persistence/Migrations/20240506223822_InboxStarvation.Designer.cs @@ -0,0 +1,101 @@ +// +using System; +using Microsoft.EntityFrameworkCore; +using Microsoft.EntityFrameworkCore.Infrastructure; +using Microsoft.EntityFrameworkCore.Migrations; +using Microsoft.EntityFrameworkCore.Storage.ValueConversion; +using Npgsql.EntityFrameworkCore.PostgreSQL.Metadata; +using TeamUp.Notifications.Infrastructure.Persistence; + +#nullable disable + +namespace TeamUp.Notifications.Infrastructure.Persistence.Migrations +{ + [DbContext(typeof(NotificationsDbContext))] + [Migration("20240506223822_InboxStarvation")] + partial class InboxStarvation + { + /// + protected override void BuildTargetModel(ModelBuilder modelBuilder) + { +#pragma warning disable 612, 618 + modelBuilder + .HasDefaultSchema("Notifications") + .HasAnnotation("ProductVersion", "8.0.4") + .HasAnnotation("Relational:MaxIdentifierLength", 63); + + NpgsqlModelBuilderExtensions.UseIdentityByDefaultColumns(modelBuilder); + + modelBuilder.Entity("TeamUp.Common.Infrastructure.Processing.Inbox.InboxMessage", b => + { + b.Property("Id") + .ValueGeneratedOnAdd() + .HasColumnType("uuid"); + + b.Property("Assembly") + .IsRequired() + .HasColumnType("text"); + + b.Property("CreatedUtc") + .HasColumnType("timestamp with time zone"); + + b.Property("Data") + .IsRequired() + .HasColumnType("text"); + + b.Property("Error") + .HasColumnType("text"); + + b.Property("FailCount") + .HasColumnType("integer"); + + b.Property("NextProcessingUtc") + .HasColumnType("timestamp with time zone"); + + b.Property("ProcessedUtc") + .HasColumnType("timestamp with time zone"); + + b.Property("Type") + .IsRequired() + .HasColumnType("text"); + + b.HasKey("Id"); + + b.ToTable("InboxMessages", "Notifications"); + }); + + modelBuilder.Entity("TeamUp.Common.Infrastructure.Processing.Outbox.OutboxMessage", b => + { + b.Property("Id") + .ValueGeneratedOnAdd() + .HasColumnType("uuid"); + + b.Property("Assembly") + .IsRequired() + .HasColumnType("text"); + + b.Property("CreatedUtc") + .HasColumnType("timestamp with time zone"); + + b.Property("Data") + .IsRequired() + .HasColumnType("text"); + + b.Property("Error") + .HasColumnType("text"); + + b.Property("ProcessedUtc") + .HasColumnType("timestamp with time zone"); + + b.Property("Type") + .IsRequired() + .HasColumnType("text"); + + b.HasKey("Id"); + + b.ToTable("OutboxMessages", "Notifications"); + }); +#pragma warning restore 612, 618 + } + } +} diff --git a/src/Modules/Notifications/TeamUp.Notifications.Infrastructure/Persistence/Migrations/20240506223822_InboxStarvation.cs b/src/Modules/Notifications/TeamUp.Notifications.Infrastructure/Persistence/Migrations/20240506223822_InboxStarvation.cs new file mode 100644 index 0000000..94e06b6 --- /dev/null +++ b/src/Modules/Notifications/TeamUp.Notifications.Infrastructure/Persistence/Migrations/20240506223822_InboxStarvation.cs @@ -0,0 +1,44 @@ +using System; +using Microsoft.EntityFrameworkCore.Migrations; + +#nullable disable + +namespace TeamUp.Notifications.Infrastructure.Persistence.Migrations +{ + /// + public partial class InboxStarvation : Migration + { + /// + protected override void Up(MigrationBuilder migrationBuilder) + { + migrationBuilder.AddColumn( + name: "FailCount", + schema: "Notifications", + table: "InboxMessages", + type: "integer", + nullable: false, + defaultValue: 0); + + migrationBuilder.AddColumn( + name: "NextProcessingUtc", + schema: "Notifications", + table: "InboxMessages", + type: "timestamp with time zone", + nullable: true); + } + + /// + protected override void Down(MigrationBuilder migrationBuilder) + { + migrationBuilder.DropColumn( + name: "FailCount", + schema: "Notifications", + table: "InboxMessages"); + + migrationBuilder.DropColumn( + name: "NextProcessingUtc", + schema: "Notifications", + table: "InboxMessages"); + } + } +} diff --git a/src/Modules/Notifications/TeamUp.Notifications.Infrastructure/Persistence/Migrations/NotificationsDbContextModelSnapshot.cs b/src/Modules/Notifications/TeamUp.Notifications.Infrastructure/Persistence/Migrations/NotificationsDbContextModelSnapshot.cs index 532fed6..eacc0d7 100644 --- a/src/Modules/Notifications/TeamUp.Notifications.Infrastructure/Persistence/Migrations/NotificationsDbContextModelSnapshot.cs +++ b/src/Modules/Notifications/TeamUp.Notifications.Infrastructure/Persistence/Migrations/NotificationsDbContextModelSnapshot.cs @@ -43,6 +43,12 @@ protected override void BuildModel(ModelBuilder modelBuilder) b.Property("Error") .HasColumnType("text"); + b.Property("FailCount") + .HasColumnType("integer"); + + b.Property("NextProcessingUtc") + .HasColumnType("timestamp with time zone"); + b.Property("ProcessedUtc") .HasColumnType("timestamp with time zone"); diff --git a/src/Modules/TeamManagement/TeamUp.TeamManagement.Infrastructure/Persistence/Migrations/20240506223856_InboxStarvation.Designer.cs b/src/Modules/TeamManagement/TeamUp.TeamManagement.Infrastructure/Persistence/Migrations/20240506223856_InboxStarvation.Designer.cs new file mode 100644 index 0000000..801b294 --- /dev/null +++ b/src/Modules/TeamManagement/TeamUp.TeamManagement.Infrastructure/Persistence/Migrations/20240506223856_InboxStarvation.Designer.cs @@ -0,0 +1,402 @@ +// +using System; +using Microsoft.EntityFrameworkCore; +using Microsoft.EntityFrameworkCore.Infrastructure; +using Microsoft.EntityFrameworkCore.Migrations; +using Microsoft.EntityFrameworkCore.Storage.ValueConversion; +using Npgsql.EntityFrameworkCore.PostgreSQL.Metadata; +using TeamUp.TeamManagement.Infrastructure; + +#nullable disable + +namespace TeamUp.TeamManagement.Infrastructure.Persistence.Migrations +{ + [DbContext(typeof(TeamManagementDbContext))] + [Migration("20240506223856_InboxStarvation")] + partial class InboxStarvation + { + /// + protected override void BuildTargetModel(ModelBuilder modelBuilder) + { +#pragma warning disable 612, 618 + modelBuilder + .HasDefaultSchema("TeamManagement") + .HasAnnotation("ProductVersion", "8.0.4") + .HasAnnotation("Relational:MaxIdentifierLength", 63); + + NpgsqlModelBuilderExtensions.UseIdentityByDefaultColumns(modelBuilder); + + modelBuilder.Entity("TeamUp.Common.Infrastructure.Processing.Inbox.InboxMessage", b => + { + b.Property("Id") + .ValueGeneratedOnAdd() + .HasColumnType("uuid"); + + b.Property("Assembly") + .IsRequired() + .HasColumnType("text"); + + b.Property("CreatedUtc") + .HasColumnType("timestamp with time zone"); + + b.Property("Data") + .IsRequired() + .HasColumnType("text"); + + b.Property("Error") + .HasColumnType("text"); + + b.Property("FailCount") + .HasColumnType("integer"); + + b.Property("NextProcessingUtc") + .HasColumnType("timestamp with time zone"); + + b.Property("ProcessedUtc") + .HasColumnType("timestamp with time zone"); + + b.Property("Type") + .IsRequired() + .HasColumnType("text"); + + b.HasKey("Id"); + + b.ToTable("InboxMessages", "TeamManagement"); + }); + + modelBuilder.Entity("TeamUp.Common.Infrastructure.Processing.Outbox.OutboxMessage", b => + { + b.Property("Id") + .ValueGeneratedOnAdd() + .HasColumnType("uuid"); + + b.Property("Assembly") + .IsRequired() + .HasColumnType("text"); + + b.Property("CreatedUtc") + .HasColumnType("timestamp with time zone"); + + b.Property("Data") + .IsRequired() + .HasColumnType("text"); + + b.Property("Error") + .HasColumnType("text"); + + b.Property("ProcessedUtc") + .HasColumnType("timestamp with time zone"); + + b.Property("Type") + .IsRequired() + .HasColumnType("text"); + + b.HasKey("Id"); + + b.ToTable("OutboxMessages", "TeamManagement"); + }); + + modelBuilder.Entity("TeamUp.TeamManagement.Domain.Aggregates.Events.Event", b => + { + b.Property("Id") + .HasColumnType("uuid"); + + b.Property("Description") + .IsRequired() + .HasColumnType("text"); + + b.Property("EventTypeId") + .HasColumnType("uuid"); + + b.Property("FromUtc") + .HasColumnType("timestamp with time zone"); + + b.Property("MeetTime") + .HasColumnType("interval"); + + b.Property("ReplyClosingTimeBeforeMeetTime") + .HasColumnType("interval"); + + b.Property("RowVersion") + .IsConcurrencyToken() + .ValueGeneratedOnAddOrUpdate() + .HasColumnType("xid") + .HasColumnName("xmin"); + + b.Property("Status") + .HasColumnType("integer"); + + b.Property("TeamId") + .HasColumnType("uuid"); + + b.Property("ToUtc") + .HasColumnType("timestamp with time zone"); + + b.HasKey("Id"); + + b.HasIndex("EventTypeId"); + + b.HasIndex("TeamId"); + + b.ToTable("Events", "TeamManagement"); + }); + + modelBuilder.Entity("TeamUp.TeamManagement.Domain.Aggregates.Events.EventResponse", b => + { + b.Property("Id") + .HasColumnType("uuid"); + + b.Property("EventId") + .HasColumnType("uuid"); + + b.Property("Message") + .IsRequired() + .HasMaxLength(255) + .HasColumnType("character varying(255)"); + + b.Property("ReplyType") + .HasColumnType("integer"); + + b.Property("TeamMemberId") + .HasColumnType("uuid"); + + b.Property("TimeStampUtc") + .HasColumnType("timestamp with time zone"); + + b.HasKey("Id"); + + b.HasIndex("EventId"); + + b.HasIndex("TeamMemberId"); + + b.HasIndex("EventId", "TeamMemberId") + .IsUnique(); + + b.ToTable("EventResponse", "TeamManagement"); + }); + + modelBuilder.Entity("TeamUp.TeamManagement.Domain.Aggregates.Invitations.Invitation", b => + { + b.Property("Id") + .HasColumnType("uuid"); + + b.Property("CreatedUtc") + .HasColumnType("timestamp with time zone"); + + b.Property("RecipientId") + .HasColumnType("uuid"); + + b.Property("TeamId") + .HasColumnType("uuid"); + + b.HasKey("Id"); + + b.HasIndex("RecipientId"); + + b.HasIndex("TeamId"); + + b.HasIndex("TeamId", "RecipientId") + .IsUnique(); + + b.ToTable("Invitations", "TeamManagement"); + }); + + modelBuilder.Entity("TeamUp.TeamManagement.Domain.Aggregates.Teams.EventType", b => + { + b.Property("Id") + .HasColumnType("uuid"); + + b.Property("Description") + .IsRequired() + .HasColumnType("text"); + + b.Property("Name") + .IsRequired() + .HasColumnType("text"); + + b.Property("TeamId") + .HasColumnType("uuid"); + + b.HasKey("Id"); + + b.HasIndex("TeamId"); + + b.ToTable("EventType", "TeamManagement"); + }); + + modelBuilder.Entity("TeamUp.TeamManagement.Domain.Aggregates.Teams.Team", b => + { + b.Property("Id") + .HasColumnType("uuid"); + + b.Property("Name") + .IsRequired() + .HasMaxLength(255) + .HasColumnType("character varying(255)"); + + b.Property("NumberOfMembers") + .HasColumnType("integer"); + + b.Property("RowVersion") + .IsConcurrencyToken() + .ValueGeneratedOnAddOrUpdate() + .HasColumnType("xid") + .HasColumnName("xmin"); + + b.HasKey("Id"); + + b.ToTable("Teams", "TeamManagement"); + }); + + modelBuilder.Entity("TeamUp.TeamManagement.Domain.Aggregates.Teams.TeamMember", b => + { + b.Property("Id") + .HasColumnType("uuid"); + + b.Property("Nickname") + .IsRequired() + .HasMaxLength(255) + .HasColumnType("character varying(255)"); + + b.Property("Role") + .HasColumnType("integer"); + + b.Property("RowVersion") + .IsConcurrencyToken() + .ValueGeneratedOnAddOrUpdate() + .HasColumnType("xid") + .HasColumnName("xmin"); + + b.Property("TeamId") + .HasColumnType("uuid"); + + b.Property("UserId") + .HasColumnType("uuid"); + + b.HasKey("Id"); + + b.HasIndex("TeamId"); + + b.HasIndex("UserId"); + + b.ToTable("TeamMember", "TeamManagement"); + }); + + modelBuilder.Entity("TeamUp.TeamManagement.Domain.Aggregates.Users.User", b => + { + b.Property("Id") + .HasColumnType("uuid"); + + b.Property("Email") + .IsRequired() + .HasMaxLength(255) + .HasColumnType("character varying(255)"); + + b.Property("Name") + .IsRequired() + .HasMaxLength(255) + .HasColumnType("character varying(255)"); + + b.Property("NumberOfOwnedTeams") + .HasColumnType("integer"); + + b.Property("RowVersion") + .IsConcurrencyToken() + .ValueGeneratedOnAddOrUpdate() + .HasColumnType("xid") + .HasColumnName("xmin"); + + b.HasKey("Id"); + + b.HasIndex("Email") + .IsUnique(); + + b.ToTable("Users", "TeamManagement"); + }); + + modelBuilder.Entity("TeamUp.TeamManagement.Domain.Aggregates.Events.Event", b => + { + b.HasOne("TeamUp.TeamManagement.Domain.Aggregates.Teams.EventType", null) + .WithMany() + .HasForeignKey("EventTypeId") + .OnDelete(DeleteBehavior.Cascade) + .IsRequired(); + + b.HasOne("TeamUp.TeamManagement.Domain.Aggregates.Teams.Team", null) + .WithMany() + .HasForeignKey("TeamId") + .OnDelete(DeleteBehavior.Cascade) + .IsRequired(); + }); + + modelBuilder.Entity("TeamUp.TeamManagement.Domain.Aggregates.Events.EventResponse", b => + { + b.HasOne("TeamUp.TeamManagement.Domain.Aggregates.Events.Event", null) + .WithMany("EventResponses") + .HasForeignKey("EventId") + .OnDelete(DeleteBehavior.Cascade) + .IsRequired(); + + b.HasOne("TeamUp.TeamManagement.Domain.Aggregates.Teams.TeamMember", null) + .WithMany() + .HasForeignKey("TeamMemberId") + .OnDelete(DeleteBehavior.Cascade) + .IsRequired(); + }); + + modelBuilder.Entity("TeamUp.TeamManagement.Domain.Aggregates.Invitations.Invitation", b => + { + b.HasOne("TeamUp.TeamManagement.Domain.Aggregates.Users.User", null) + .WithMany() + .HasForeignKey("RecipientId") + .OnDelete(DeleteBehavior.Cascade) + .IsRequired(); + + b.HasOne("TeamUp.TeamManagement.Domain.Aggregates.Teams.Team", null) + .WithMany() + .HasForeignKey("TeamId") + .OnDelete(DeleteBehavior.Cascade) + .IsRequired(); + }); + + modelBuilder.Entity("TeamUp.TeamManagement.Domain.Aggregates.Teams.EventType", b => + { + b.HasOne("TeamUp.TeamManagement.Domain.Aggregates.Teams.Team", null) + .WithMany("EventTypes") + .HasForeignKey("TeamId") + .OnDelete(DeleteBehavior.Cascade) + .IsRequired(); + }); + + modelBuilder.Entity("TeamUp.TeamManagement.Domain.Aggregates.Teams.TeamMember", b => + { + b.HasOne("TeamUp.TeamManagement.Domain.Aggregates.Teams.Team", "Team") + .WithMany("Members") + .HasForeignKey("TeamId") + .OnDelete(DeleteBehavior.Cascade) + .IsRequired(); + + b.HasOne("TeamUp.TeamManagement.Domain.Aggregates.Users.User", null) + .WithMany() + .HasForeignKey("UserId") + .OnDelete(DeleteBehavior.Cascade) + .IsRequired(); + + b.Navigation("Team"); + }); + + modelBuilder.Entity("TeamUp.TeamManagement.Domain.Aggregates.Events.Event", b => + { + b.Navigation("EventResponses"); + }); + + modelBuilder.Entity("TeamUp.TeamManagement.Domain.Aggregates.Teams.Team", b => + { + b.Navigation("EventTypes"); + + b.Navigation("Members"); + }); +#pragma warning restore 612, 618 + } + } +} diff --git a/src/Modules/TeamManagement/TeamUp.TeamManagement.Infrastructure/Persistence/Migrations/20240506223856_InboxStarvation.cs b/src/Modules/TeamManagement/TeamUp.TeamManagement.Infrastructure/Persistence/Migrations/20240506223856_InboxStarvation.cs new file mode 100644 index 0000000..8b97aa8 --- /dev/null +++ b/src/Modules/TeamManagement/TeamUp.TeamManagement.Infrastructure/Persistence/Migrations/20240506223856_InboxStarvation.cs @@ -0,0 +1,44 @@ +using System; +using Microsoft.EntityFrameworkCore.Migrations; + +#nullable disable + +namespace TeamUp.TeamManagement.Infrastructure.Persistence.Migrations +{ + /// + public partial class InboxStarvation : Migration + { + /// + protected override void Up(MigrationBuilder migrationBuilder) + { + migrationBuilder.AddColumn( + name: "FailCount", + schema: "TeamManagement", + table: "InboxMessages", + type: "integer", + nullable: false, + defaultValue: 0); + + migrationBuilder.AddColumn( + name: "NextProcessingUtc", + schema: "TeamManagement", + table: "InboxMessages", + type: "timestamp with time zone", + nullable: true); + } + + /// + protected override void Down(MigrationBuilder migrationBuilder) + { + migrationBuilder.DropColumn( + name: "FailCount", + schema: "TeamManagement", + table: "InboxMessages"); + + migrationBuilder.DropColumn( + name: "NextProcessingUtc", + schema: "TeamManagement", + table: "InboxMessages"); + } + } +} diff --git a/src/Modules/TeamManagement/TeamUp.TeamManagement.Infrastructure/Persistence/Migrations/TeamManagementDbContextModelSnapshot.cs b/src/Modules/TeamManagement/TeamUp.TeamManagement.Infrastructure/Persistence/Migrations/TeamManagementDbContextModelSnapshot.cs index 10e80f7..520c9fd 100644 --- a/src/Modules/TeamManagement/TeamUp.TeamManagement.Infrastructure/Persistence/Migrations/TeamManagementDbContextModelSnapshot.cs +++ b/src/Modules/TeamManagement/TeamUp.TeamManagement.Infrastructure/Persistence/Migrations/TeamManagementDbContextModelSnapshot.cs @@ -43,6 +43,12 @@ protected override void BuildModel(ModelBuilder modelBuilder) b.Property("Error") .HasColumnType("text"); + b.Property("FailCount") + .HasColumnType("integer"); + + b.Property("NextProcessingUtc") + .HasColumnType("timestamp with time zone"); + b.Property("ProcessedUtc") .HasColumnType("timestamp with time zone"); diff --git a/src/Modules/UserAccess/TeamUp.UserAccess.Infrastructure/Persistence/Migrations/20240506223920_InboxStarvation.Designer.cs b/src/Modules/UserAccess/TeamUp.UserAccess.Infrastructure/Persistence/Migrations/20240506223920_InboxStarvation.Designer.cs new file mode 100644 index 0000000..ca643b4 --- /dev/null +++ b/src/Modules/UserAccess/TeamUp.UserAccess.Infrastructure/Persistence/Migrations/20240506223920_InboxStarvation.Designer.cs @@ -0,0 +1,137 @@ +// +using System; +using Microsoft.EntityFrameworkCore; +using Microsoft.EntityFrameworkCore.Infrastructure; +using Microsoft.EntityFrameworkCore.Migrations; +using Microsoft.EntityFrameworkCore.Storage.ValueConversion; +using Npgsql.EntityFrameworkCore.PostgreSQL.Metadata; +using TeamUp.UserAccess.Infrastructure.Persistence; + +#nullable disable + +namespace TeamUp.UserAccess.Infrastructure.Persistence.Migrations +{ + [DbContext(typeof(UserAccessDbContext))] + [Migration("20240506223920_InboxStarvation")] + partial class InboxStarvation + { + /// + protected override void BuildTargetModel(ModelBuilder modelBuilder) + { +#pragma warning disable 612, 618 + modelBuilder + .HasDefaultSchema("UserAccess") + .HasAnnotation("ProductVersion", "8.0.4") + .HasAnnotation("Relational:MaxIdentifierLength", 63); + + NpgsqlModelBuilderExtensions.UseIdentityByDefaultColumns(modelBuilder); + + modelBuilder.Entity("TeamUp.Common.Infrastructure.Processing.Inbox.InboxMessage", b => + { + b.Property("Id") + .ValueGeneratedOnAdd() + .HasColumnType("uuid"); + + b.Property("Assembly") + .IsRequired() + .HasColumnType("text"); + + b.Property("CreatedUtc") + .HasColumnType("timestamp with time zone"); + + b.Property("Data") + .IsRequired() + .HasColumnType("text"); + + b.Property("Error") + .HasColumnType("text"); + + b.Property("FailCount") + .HasColumnType("integer"); + + b.Property("NextProcessingUtc") + .HasColumnType("timestamp with time zone"); + + b.Property("ProcessedUtc") + .HasColumnType("timestamp with time zone"); + + b.Property("Type") + .IsRequired() + .HasColumnType("text"); + + b.HasKey("Id"); + + b.ToTable("InboxMessages", "UserAccess"); + }); + + modelBuilder.Entity("TeamUp.Common.Infrastructure.Processing.Outbox.OutboxMessage", b => + { + b.Property("Id") + .ValueGeneratedOnAdd() + .HasColumnType("uuid"); + + b.Property("Assembly") + .IsRequired() + .HasColumnType("text"); + + b.Property("CreatedUtc") + .HasColumnType("timestamp with time zone"); + + b.Property("Data") + .IsRequired() + .HasColumnType("text"); + + b.Property("Error") + .HasColumnType("text"); + + b.Property("ProcessedUtc") + .HasColumnType("timestamp with time zone"); + + b.Property("Type") + .IsRequired() + .HasColumnType("text"); + + b.HasKey("Id"); + + b.ToTable("OutboxMessages", "UserAccess"); + }); + + modelBuilder.Entity("TeamUp.UserAccess.Domain.User", b => + { + b.Property("Id") + .HasColumnType("uuid"); + + b.Property("Email") + .IsRequired() + .HasMaxLength(255) + .HasColumnType("character varying(255)"); + + b.Property("Name") + .IsRequired() + .HasMaxLength(255) + .HasColumnType("character varying(255)"); + + b.Property("Password") + .IsRequired() + .HasColumnType("bytea"); + + b.Property("RowVersion") + .IsConcurrencyToken() + .ValueGeneratedOnAddOrUpdate() + .HasColumnType("xid") + .HasColumnName("xmin"); + + b.Property("State") + .HasColumnType("integer"); + + b.HasKey("Id"); + + b.HasIndex("Email") + .IsUnique(); + + b.ToTable("Users", "UserAccess"); + }); +#pragma warning restore 612, 618 + } + } +} diff --git a/src/Modules/UserAccess/TeamUp.UserAccess.Infrastructure/Persistence/Migrations/20240506223920_InboxStarvation.cs b/src/Modules/UserAccess/TeamUp.UserAccess.Infrastructure/Persistence/Migrations/20240506223920_InboxStarvation.cs new file mode 100644 index 0000000..abb3c87 --- /dev/null +++ b/src/Modules/UserAccess/TeamUp.UserAccess.Infrastructure/Persistence/Migrations/20240506223920_InboxStarvation.cs @@ -0,0 +1,44 @@ +using System; +using Microsoft.EntityFrameworkCore.Migrations; + +#nullable disable + +namespace TeamUp.UserAccess.Infrastructure.Persistence.Migrations +{ + /// + public partial class InboxStarvation : Migration + { + /// + protected override void Up(MigrationBuilder migrationBuilder) + { + migrationBuilder.AddColumn( + name: "FailCount", + schema: "UserAccess", + table: "InboxMessages", + type: "integer", + nullable: false, + defaultValue: 0); + + migrationBuilder.AddColumn( + name: "NextProcessingUtc", + schema: "UserAccess", + table: "InboxMessages", + type: "timestamp with time zone", + nullable: true); + } + + /// + protected override void Down(MigrationBuilder migrationBuilder) + { + migrationBuilder.DropColumn( + name: "FailCount", + schema: "UserAccess", + table: "InboxMessages"); + + migrationBuilder.DropColumn( + name: "NextProcessingUtc", + schema: "UserAccess", + table: "InboxMessages"); + } + } +} diff --git a/src/Modules/UserAccess/TeamUp.UserAccess.Infrastructure/Persistence/Migrations/UserAccessDbContextModelSnapshot.cs b/src/Modules/UserAccess/TeamUp.UserAccess.Infrastructure/Persistence/Migrations/UserAccessDbContextModelSnapshot.cs index 53330c0..6dbe22b 100644 --- a/src/Modules/UserAccess/TeamUp.UserAccess.Infrastructure/Persistence/Migrations/UserAccessDbContextModelSnapshot.cs +++ b/src/Modules/UserAccess/TeamUp.UserAccess.Infrastructure/Persistence/Migrations/UserAccessDbContextModelSnapshot.cs @@ -43,6 +43,12 @@ protected override void BuildModel(ModelBuilder modelBuilder) b.Property("Error") .HasColumnType("text"); + b.Property("FailCount") + .HasColumnType("integer"); + + b.Property("NextProcessingUtc") + .HasColumnType("timestamp with time zone"); + b.Property("ProcessedUtc") .HasColumnType("timestamp with time zone"); diff --git a/tests/TeamUp.Tests.EndToEnd/Mocks/InboxConsumerWithCallbacksFacade.cs b/tests/TeamUp.Tests.EndToEnd/Mocks/InboxConsumerWithCallbacksFacade.cs index e2370c5..d8a1759 100644 --- a/tests/TeamUp.Tests.EndToEnd/Mocks/InboxConsumerWithCallbacksFacade.cs +++ b/tests/TeamUp.Tests.EndToEnd/Mocks/InboxConsumerWithCallbacksFacade.cs @@ -24,7 +24,7 @@ public async Task DispatchIntegrationEventsAsync(DbContext dbContext, Cancellati _logger.LogInformation("Retrieving inbox messages."); //get unpublished integration events - var messages = await InboxConsumer.GetInboxAsync(dbContext, ct); + var messages = await _inboxConsumer.GetInboxAsync(dbContext, ct); _logger.LogInformation("Publishing inbox messages.");