From 732878f734a71e66060772ed0fe799e72c5b5644 Mon Sep 17 00:00:00 2001 From: Savorboard Date: Tue, 11 Jul 2017 01:11:06 +0800 Subject: [PATCH 01/68] =?UTF-8?q?=E9=87=8D=E5=86=99=E5=AD=98=E5=82=A8?= =?UTF-8?q?=E6=A8=A1=E5=9D=97=E3=80=82?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- CAP.sln | 14 ++ samples/Sample.Kafka/AppDbContext.cs | 18 +- .../Controllers/ValuesController.cs | 10 +- .../20170629074148_InitCreate.Designer.cs | 67 ------ .../Migrations/20170629074148_InitCreate.cs | 55 ----- .../Migrations/AppDbContextModelSnapshot.cs | 66 ------ samples/Sample.Kafka/Startup.cs | 4 +- .../CAP.BuilderExtensions.cs | 21 +- .../CAP.EFOptions.cs | 17 ++ .../EFStorage.cs | 37 ++++ .../EFStorageConnection.cs | 202 ++++++++++++++++++ .../EFStorageTransaction.cs | 67 ++++++ .../FetchedMessage.cs | 11 + src/DotNetCore.CAP/IFetchedMessage.cs | 13 ++ src/DotNetCore.CAP/IStorage.cs | 16 ++ src/DotNetCore.CAP/IStorageConnection.cs | 68 ++++++ src/DotNetCore.CAP/IStorageTransaction.cs | 19 ++ .../CapReceivedMessage.cs | 2 +- .../CapSentMessage.cs | 4 +- 19 files changed, 499 insertions(+), 212 deletions(-) delete mode 100644 samples/Sample.Kafka/Migrations/20170629074148_InitCreate.Designer.cs delete mode 100644 samples/Sample.Kafka/Migrations/20170629074148_InitCreate.cs delete mode 100644 samples/Sample.Kafka/Migrations/AppDbContextModelSnapshot.cs create mode 100644 src/DotNetCore.CAP.EntityFrameworkCore/CAP.EFOptions.cs create mode 100644 src/DotNetCore.CAP.EntityFrameworkCore/EFStorage.cs create mode 100644 src/DotNetCore.CAP.EntityFrameworkCore/EFStorageConnection.cs create mode 100644 src/DotNetCore.CAP.EntityFrameworkCore/EFStorageTransaction.cs create mode 100644 src/DotNetCore.CAP.EntityFrameworkCore/FetchedMessage.cs create mode 100644 src/DotNetCore.CAP/IFetchedMessage.cs create mode 100644 src/DotNetCore.CAP/IStorage.cs create mode 100644 src/DotNetCore.CAP/IStorageConnection.cs create mode 100644 src/DotNetCore.CAP/IStorageTransaction.cs rename src/DotNetCore.CAP/{Infrastructure => Models}/CapReceivedMessage.cs (96%) rename src/DotNetCore.CAP/{Infrastructure => Models}/CapSentMessage.cs (90%) diff --git a/CAP.sln b/CAP.sln index 26769fb..b1d9467 100644 --- a/CAP.sln +++ b/CAP.sln @@ -59,6 +59,10 @@ Project("{9A19103F-16F7-4668-BE54-9A1E7A4F7556}") = "DotNetCore.CAP.EntityFramew EndProject Project("{9A19103F-16F7-4668-BE54-9A1E7A4F7556}") = "DotNetCore.CAP.Test", "test\DotNetCore.CAP.Test\DotNetCore.CAP.Test.csproj", "{F608B509-A99B-4AC7-8227-42051DD4A578}" EndProject +Project("{9A19103F-16F7-4668-BE54-9A1E7A4F7556}") = "WebApp1", "..\..\CAPTests\WebApp1\WebApp1.csproj", "{880F8E24-5B18-43E6-A75B-8AD7B24FCBEC}" +EndProject +Project("{9A19103F-16F7-4668-BE54-9A1E7A4F7556}") = "WebApp2", "..\..\CAPTests\WebApp2\WebApp2.csproj", "{C190100E-EF0D-4C63-9189-F29D0E64D66E}" +EndProject Global GlobalSection(SolutionConfigurationPlatforms) = preSolution Debug|Any CPU = Debug|Any CPU @@ -93,6 +97,14 @@ Global {F608B509-A99B-4AC7-8227-42051DD4A578}.Debug|Any CPU.Build.0 = Debug|Any CPU {F608B509-A99B-4AC7-8227-42051DD4A578}.Release|Any CPU.ActiveCfg = Release|Any CPU {F608B509-A99B-4AC7-8227-42051DD4A578}.Release|Any CPU.Build.0 = Release|Any CPU + {880F8E24-5B18-43E6-A75B-8AD7B24FCBEC}.Debug|Any CPU.ActiveCfg = Debug|Any CPU + {880F8E24-5B18-43E6-A75B-8AD7B24FCBEC}.Debug|Any CPU.Build.0 = Debug|Any CPU + {880F8E24-5B18-43E6-A75B-8AD7B24FCBEC}.Release|Any CPU.ActiveCfg = Release|Any CPU + {880F8E24-5B18-43E6-A75B-8AD7B24FCBEC}.Release|Any CPU.Build.0 = Release|Any CPU + {C190100E-EF0D-4C63-9189-F29D0E64D66E}.Debug|Any CPU.ActiveCfg = Debug|Any CPU + {C190100E-EF0D-4C63-9189-F29D0E64D66E}.Debug|Any CPU.Build.0 = Debug|Any CPU + {C190100E-EF0D-4C63-9189-F29D0E64D66E}.Release|Any CPU.ActiveCfg = Release|Any CPU + {C190100E-EF0D-4C63-9189-F29D0E64D66E}.Release|Any CPU.Build.0 = Release|Any CPU EndGlobalSection GlobalSection(SolutionProperties) = preSolution HideSolutionNode = FALSE @@ -106,5 +118,7 @@ Global {9961B80E-0718-4280-B2A0-271B003DE26B} = {9B2AE124-6636-4DE9-83A3-70360DABD0C4} {69370370-9873-4D6A-965D-D1E16694047D} = {C09CDAB0-6DD4-46E9-B7F3-3EF2A4741EA0} {F608B509-A99B-4AC7-8227-42051DD4A578} = {C09CDAB0-6DD4-46E9-B7F3-3EF2A4741EA0} + {880F8E24-5B18-43E6-A75B-8AD7B24FCBEC} = {3A6B6931-A123-477A-9469-8B468B5385AF} + {C190100E-EF0D-4C63-9189-F29D0E64D66E} = {3A6B6931-A123-477A-9469-8B468B5385AF} EndGlobalSection EndGlobal diff --git a/samples/Sample.Kafka/AppDbContext.cs b/samples/Sample.Kafka/AppDbContext.cs index d1900a1..361929e 100644 --- a/samples/Sample.Kafka/AppDbContext.cs +++ b/samples/Sample.Kafka/AppDbContext.cs @@ -2,30 +2,18 @@ using System.Collections.Generic; using System.Linq; using System.Threading.Tasks; +using DotNetCore.CAP.EntityFrameworkCore; using DotNetCore.CAP.Infrastructure; using JetBrains.Annotations; using Microsoft.EntityFrameworkCore; namespace Sample.Kafka { - public class AppDbContext : DbContext + public class AppDbContext : CapDbContext { - - public DbSet SentMessages { get; set; } - - public DbSet ReceivedMessages { get; set; } - protected override void OnConfiguring(DbContextOptionsBuilder optionsBuilder) { - optionsBuilder.UseSqlServer("Server=192.168.2.206;Initial Catalog=Test;User Id=cmswuliu;Password=h7xY81agBn*Veiu3;MultipleActiveResultSets=True"); - } - - protected override void OnModelCreating(ModelBuilder modelBuilder) - { - modelBuilder.Entity().Property(x => x.StatusName).HasMaxLength(50); - modelBuilder.Entity().Property(x => x.StatusName).HasMaxLength(50); - - base.OnModelCreating(modelBuilder); + optionsBuilder.UseSqlServer("Server=DESKTOP-M9R8T31;Initial Catalog=WebApp1;User Id=sa;Password=P@ssw0rd;MultipleActiveResultSets=True"); } } } diff --git a/samples/Sample.Kafka/Controllers/ValuesController.cs b/samples/Sample.Kafka/Controllers/ValuesController.cs index 3c09caf..1e36aff 100644 --- a/samples/Sample.Kafka/Controllers/ValuesController.cs +++ b/samples/Sample.Kafka/Controllers/ValuesController.cs @@ -33,9 +33,15 @@ namespace Sample.Kafka.Controllers } [Route("~/send")] - public async Task SendTopic() + public async Task SendTopic([FromServices] AppDbContext dbContext) { - await _producer.PublishAsync("zzwl.topic.finace.callBack", new Person { Name = "Test", Age = 11 }); + using (var trans = dbContext.Database.BeginTransaction()) + { + await _producer.PublishAsync("zzwl.topic.finace.callBack", new Person { Name = "Test", Age = 11 }); + + trans.Commit(); + } + return Ok(); } diff --git a/samples/Sample.Kafka/Migrations/20170629074148_InitCreate.Designer.cs b/samples/Sample.Kafka/Migrations/20170629074148_InitCreate.Designer.cs deleted file mode 100644 index ff7d387..0000000 --- a/samples/Sample.Kafka/Migrations/20170629074148_InitCreate.Designer.cs +++ /dev/null @@ -1,67 +0,0 @@ -using System; -using Microsoft.EntityFrameworkCore; -using Microsoft.EntityFrameworkCore.Infrastructure; -using Microsoft.EntityFrameworkCore.Metadata; -using Microsoft.EntityFrameworkCore.Migrations; -using Sample.Kafka; - -namespace Sample.Kafka.Migrations -{ - [DbContext(typeof(AppDbContext))] - [Migration("20170629074148_InitCreate")] - partial class InitCreate - { - protected override void BuildTargetModel(ModelBuilder modelBuilder) - { - modelBuilder - .HasAnnotation("ProductVersion", "1.1.2") - .HasAnnotation("SqlServer:ValueGenerationStrategy", SqlServerValueGenerationStrategy.IdentityColumn); - - modelBuilder.Entity("DotNetCore.CAP.Infrastructure.CapReceivedMessage", b => - { - b.Property("Id") - .ValueGeneratedOnAdd(); - - b.Property("Added"); - - b.Property("Content"); - - b.Property("KeyName"); - - b.Property("LastRun"); - - b.Property("Retries"); - - b.Property("StatusName") - .HasMaxLength(50); - - b.HasKey("Id"); - - b.ToTable("ReceivedMessages"); - }); - - modelBuilder.Entity("DotNetCore.CAP.Infrastructure.CapSentMessage", b => - { - b.Property("Id") - .ValueGeneratedOnAdd(); - - b.Property("Added"); - - b.Property("Content"); - - b.Property("KeyName"); - - b.Property("LastRun"); - - b.Property("Retries"); - - b.Property("StatusName") - .HasMaxLength(50); - - b.HasKey("Id"); - - b.ToTable("SentMessages"); - }); - } - } -} diff --git a/samples/Sample.Kafka/Migrations/20170629074148_InitCreate.cs b/samples/Sample.Kafka/Migrations/20170629074148_InitCreate.cs deleted file mode 100644 index 9168f8c..0000000 --- a/samples/Sample.Kafka/Migrations/20170629074148_InitCreate.cs +++ /dev/null @@ -1,55 +0,0 @@ -using System; -using System.Collections.Generic; -using Microsoft.EntityFrameworkCore.Migrations; - -namespace Sample.Kafka.Migrations -{ - public partial class InitCreate : Migration - { - protected override void Up(MigrationBuilder migrationBuilder) - { - migrationBuilder.CreateTable( - name: "ReceivedMessages", - columns: table => new - { - Id = table.Column(nullable: false), - Added = table.Column(nullable: false), - Content = table.Column(nullable: true), - KeyName = table.Column(nullable: true), - LastRun = table.Column(nullable: false), - Retries = table.Column(nullable: false), - StatusName = table.Column(maxLength: 50, nullable: true) - }, - constraints: table => - { - table.PrimaryKey("PK_ReceivedMessages", x => x.Id); - }); - - migrationBuilder.CreateTable( - name: "SentMessages", - columns: table => new - { - Id = table.Column(nullable: false), - Added = table.Column(nullable: false), - Content = table.Column(nullable: true), - KeyName = table.Column(nullable: true), - LastRun = table.Column(nullable: false), - Retries = table.Column(nullable: false), - StatusName = table.Column(maxLength: 50, nullable: true) - }, - constraints: table => - { - table.PrimaryKey("PK_SentMessages", x => x.Id); - }); - } - - protected override void Down(MigrationBuilder migrationBuilder) - { - migrationBuilder.DropTable( - name: "ReceivedMessages"); - - migrationBuilder.DropTable( - name: "SentMessages"); - } - } -} diff --git a/samples/Sample.Kafka/Migrations/AppDbContextModelSnapshot.cs b/samples/Sample.Kafka/Migrations/AppDbContextModelSnapshot.cs deleted file mode 100644 index cd7fc0b..0000000 --- a/samples/Sample.Kafka/Migrations/AppDbContextModelSnapshot.cs +++ /dev/null @@ -1,66 +0,0 @@ -using System; -using Microsoft.EntityFrameworkCore; -using Microsoft.EntityFrameworkCore.Infrastructure; -using Microsoft.EntityFrameworkCore.Metadata; -using Microsoft.EntityFrameworkCore.Migrations; -using Sample.Kafka; - -namespace Sample.Kafka.Migrations -{ - [DbContext(typeof(AppDbContext))] - partial class AppDbContextModelSnapshot : ModelSnapshot - { - protected override void BuildModel(ModelBuilder modelBuilder) - { - modelBuilder - .HasAnnotation("ProductVersion", "1.1.2") - .HasAnnotation("SqlServer:ValueGenerationStrategy", SqlServerValueGenerationStrategy.IdentityColumn); - - modelBuilder.Entity("DotNetCore.CAP.Infrastructure.CapReceivedMessage", b => - { - b.Property("Id") - .ValueGeneratedOnAdd(); - - b.Property("Added"); - - b.Property("Content"); - - b.Property("KeyName"); - - b.Property("LastRun"); - - b.Property("Retries"); - - b.Property("StatusName") - .HasMaxLength(50); - - b.HasKey("Id"); - - b.ToTable("ReceivedMessages"); - }); - - modelBuilder.Entity("DotNetCore.CAP.Infrastructure.CapSentMessage", b => - { - b.Property("Id") - .ValueGeneratedOnAdd(); - - b.Property("Added"); - - b.Property("Content"); - - b.Property("KeyName"); - - b.Property("LastRun"); - - b.Property("Retries"); - - b.Property("StatusName") - .HasMaxLength(50); - - b.HasKey("Id"); - - b.ToTable("SentMessages"); - }); - } - } -} diff --git a/samples/Sample.Kafka/Startup.cs b/samples/Sample.Kafka/Startup.cs index d234b37..1858212 100644 --- a/samples/Sample.Kafka/Startup.cs +++ b/samples/Sample.Kafka/Startup.cs @@ -29,9 +29,7 @@ namespace Sample.Kafka .AddEntityFrameworkStores() .AddRabbitMQ(x => { - x.HostName = "192.168.2.206"; - x.UserName = "admin"; - x.Password = "123123"; + x.HostName = "localhost"; }); //.AddKafka(x => x.Servers = ""); diff --git a/src/DotNetCore.CAP.EntityFrameworkCore/CAP.BuilderExtensions.cs b/src/DotNetCore.CAP.EntityFrameworkCore/CAP.BuilderExtensions.cs index 709eb99..5cd1553 100644 --- a/src/DotNetCore.CAP.EntityFrameworkCore/CAP.BuilderExtensions.cs +++ b/src/DotNetCore.CAP.EntityFrameworkCore/CAP.BuilderExtensions.cs @@ -1,4 +1,5 @@ -using DotNetCore.CAP; +using System; +using DotNetCore.CAP; using DotNetCore.CAP.EntityFrameworkCore; using Microsoft.EntityFrameworkCore; @@ -19,7 +20,25 @@ namespace Microsoft.Extensions.DependencyInjection { builder.Services.AddScoped>(); + builder.Services.AddScoped(); + builder.Services.AddScoped>(); + return builder; } + + + public static CapBuilder AddEntityFrameworkStores(this CapBuilder builder, Action options) + where TContext : DbContext + { + builder.Services.AddScoped>(); + + builder.Services.AddScoped(); + builder.Services.AddScoped>(); + builder.Services.Configure(options); + + return builder; + } + + } } \ No newline at end of file diff --git a/src/DotNetCore.CAP.EntityFrameworkCore/CAP.EFOptions.cs b/src/DotNetCore.CAP.EntityFrameworkCore/CAP.EFOptions.cs new file mode 100644 index 0000000..cdb877b --- /dev/null +++ b/src/DotNetCore.CAP.EntityFrameworkCore/CAP.EFOptions.cs @@ -0,0 +1,17 @@ +using System; +using System.Collections.Generic; +using System.Text; + +namespace DotNetCore.CAP.EntityFrameworkCore +{ + public class EFOptions + { + public const string DefaultSchema = "cap"; + + /// + /// Gets or sets the schema to use when creating database objects. + /// Default is . + /// + public string Schema { get; set; } = DefaultSchema; + } +} diff --git a/src/DotNetCore.CAP.EntityFrameworkCore/EFStorage.cs b/src/DotNetCore.CAP.EntityFrameworkCore/EFStorage.cs new file mode 100644 index 0000000..f69b059 --- /dev/null +++ b/src/DotNetCore.CAP.EntityFrameworkCore/EFStorage.cs @@ -0,0 +1,37 @@ +using System; +using System.Threading; +using System.Threading.Tasks; +using Microsoft.EntityFrameworkCore; +using Microsoft.Extensions.DependencyInjection; +using Microsoft.Extensions.Logging; + +namespace DotNetCore.CAP.EntityFrameworkCore +{ + public class EFStorage : IStorage + { + private IServiceProvider _provider; + private ILogger _logger; + + public EFStorage( + IServiceProvider provider, + ILogger logger) + { + _provider = provider; + _logger = logger; + } + + public async Task InitializeAsync(CancellationToken cancellationToken) + { + using (var scope = _provider.CreateScope()) + { + if (cancellationToken.IsCancellationRequested) return; + + var provider = scope.ServiceProvider; + var context = provider.GetRequiredService(); + + _logger.LogDebug("Ensuring all migrations are applied to Jobs database."); + await context.Database.MigrateAsync(cancellationToken); + } + } + } +} diff --git a/src/DotNetCore.CAP.EntityFrameworkCore/EFStorageConnection.cs b/src/DotNetCore.CAP.EntityFrameworkCore/EFStorageConnection.cs new file mode 100644 index 0000000..257f682 --- /dev/null +++ b/src/DotNetCore.CAP.EntityFrameworkCore/EFStorageConnection.cs @@ -0,0 +1,202 @@ +using System; +using System.Data; +using System.Data.SqlClient; +using System.Linq; +using System.Threading.Tasks; +using Dapper; +using DotNetCore.CAP.Models; +using Microsoft.EntityFrameworkCore; +using Microsoft.EntityFrameworkCore.Storage; +using Microsoft.Extensions.Options; +using MR.AspNetCore.Jobs.Models; +using MR.AspNetCore.Jobs.Server; +using MR.AspNetCore.Jobs.Server.States; + +namespace DotNetCore.CAP.EntityFrameworkCore +{ + public class EFStorageConnection : IStorageConnection where TContext : DbContext + { + private readonly CapDbContext _context; + private readonly EFOptions _options; + + public EFStorageConnection( + CapDbContext context, + IOptions options) + { + _context = context; + _options = options.Value; + } + + public CapDbContext Context => _context; + + public EFOptions Options => _options; + + + + public Task StoreCronJobAsync(CronJob job) + { + if (job == null) throw new ArgumentNullException(nameof(job)); + + _context.Add(job); + return _context.SaveChangesAsync(); + } + + public Task AttachCronJobAsync(CronJob job) + { + if (job == null) throw new ArgumentNullException(nameof(job)); + + _context.Attach(job); + return Task.FromResult(true); + } + + public Task UpdateCronJobAsync(CronJob job) + { + if (job == null) throw new ArgumentNullException(nameof(job)); + + return _context.SaveChangesAsync(); + } + + public Task GetCronJobsAsync() + { + return _context.CronJobs.ToArrayAsync(); + } + + public async Task RemoveCronJobAsync(string name) + { + var cronJob = await _context.CronJobs.FirstOrDefaultAsync(j => j.Name == name); + if (cronJob != null) + { + _context.Remove(cronJob); + await _context.SaveChangesAsync(); + } + } + + public IStorageTransaction CreateTransaction() + { + return new EFStorageTransaction(this); + } + + public void Dispose() + { + } + + private DateTime? NormalizeDateTime(DateTime? dateTime) + { + if (!dateTime.HasValue) return dateTime; + if (dateTime == DateTime.MinValue) + { + return new DateTime(1754, 1, 1, 0, 0, 0, DateTimeKind.Utc); + } + return dateTime; + } + + + + public Task StoreSentMessageAsync(CapSentMessage message) + { + if (message == null) throw new ArgumentNullException(nameof(message)); + + message.LastRun = NormalizeDateTime(message.LastRun); + + _context.Add(message); + return _context.SaveChangesAsync(); + } + + public Task GetSentMessageAsync(string id) + { + return _context.CapSentMessages.FirstOrDefaultAsync(x => x.Id == id); + } + + public Task FetchNextJobAsync() + { + + } + + public async Task GetNextJobToBeEnqueuedAsync() + { + var sql = $@" +SELECT TOP (1) * +FROM [{_options.Schema}].[{nameof(JobsDbContext.Jobs)}] WITH (readpast) +WHERE (Due IS NULL OR Due < GETUTCDATE()) AND StateName = '{ScheduledState.StateName}'"; + + var connection = _context.GetDbConnection(); + + var job = (await connection.QueryAsync(sql)).FirstOrDefault(); + + if (job != null) + { + _context.Attach(job); + } + + return job; + } + + public Task FetchNextSentMessageAsync() + { + var sql = $@" +DELETE TOP (1) +FROM [{_options.Schema}].[{nameof(CapDbContext.CapSentMessages)}] WITH (readpast, updlock, rowlock) +OUTPUT DELETED.Id"; + + //return FetchNextDelayedMessageCoreAsync(sql); + throw new NotImplementedException(); + } + + //private async Task FetchNextDelayedMessageCoreAsync(string sql, object args = null) + //{ + // FetchedMessage fetchedJob = null; + // var connection = _context.Database.GetDbConnection(); + // var transaction = _context.Database.CurrentTransaction; + // transaction = transaction ?? await _context.Database.BeginTransactionAsync(IsolationLevel.ReadCommitted); + + // try + // { + // fetchedJob = + // (await _context...QueryAsync(sql, args, transaction.GetDbTransaction())) + // .FirstOrDefault(); + // } + // catch (SqlException) + // { + // transaction.Dispose(); + // throw; + // } + + // if (fetchedJob == null) + // { + // transaction.Rollback(); + // transaction.Dispose(); + // return null; + // } + + // return new SqlServerFetchedJob( + // fetchedJob.JobId, + // connection, + // transaction); + //} + + public Task GetNextSentMessageToBeEnqueuedAsync() + { + throw new NotImplementedException(); + } + + public Task StoreReceivedMessageAsync(CapReceivedMessage message) + { + throw new NotImplementedException(); + } + + public Task GetReceivedMessageAsync(string id) + { + throw new NotImplementedException(); + } + + public Task FetchNextReceivedMessageAsync() + { + throw new NotImplementedException(); + } + + public Task GetNextReceviedMessageToBeEnqueuedAsync() + { + throw new NotImplementedException(); + } + } +} diff --git a/src/DotNetCore.CAP.EntityFrameworkCore/EFStorageTransaction.cs b/src/DotNetCore.CAP.EntityFrameworkCore/EFStorageTransaction.cs new file mode 100644 index 0000000..d511d6a --- /dev/null +++ b/src/DotNetCore.CAP.EntityFrameworkCore/EFStorageTransaction.cs @@ -0,0 +1,67 @@ +using System; +using System.Threading.Tasks; +using DotNetCore.CAP.Models; + +namespace DotNetCore.CAP.EntityFrameworkCore +{ + public class EFStorageTransaction : IStorageTransaction, IDisposable + { + private EFStorageConnection _connection; + + public EFStorageTransaction(EFStorageConnection connection) + { + _connection = connection; + } + + public void UpdateJob(Job job) + { + if (job == null) throw new ArgumentNullException(nameof(job)); + + // NOOP. EF will detect changes. + } + + public void EnqueueJob(Job job) + { + + } + + public Task CommitAsync() + { + return _connection.Context.SaveChangesAsync(); + } + + public void Dispose() + { + } + + public void UpdateMessage(CapSentMessage message) + { + throw new NotImplementedException(); + } + + public void UpdateMessage(CapReceivedMessage message) + { + throw new NotImplementedException(); + } + + public void EnqueueMessage(CapSentMessage message) + { + if (job == null) throw new ArgumentNullException(nameof(job)); + + _connection.Context.Add(new JobQueue + { + JobId = job.Id + }); + } + + public void EnqueueMessage(CapReceivedMessage message) + { + if (job == null) throw new ArgumentNullException(nameof(job)); + + _connection.Context.Add(new JobQueue + { + JobId = job.Id + }); + } + } +} diff --git a/src/DotNetCore.CAP.EntityFrameworkCore/FetchedMessage.cs b/src/DotNetCore.CAP.EntityFrameworkCore/FetchedMessage.cs new file mode 100644 index 0000000..dd662e1 --- /dev/null +++ b/src/DotNetCore.CAP.EntityFrameworkCore/FetchedMessage.cs @@ -0,0 +1,11 @@ +using System; +using System.Collections.Generic; +using System.Text; + +namespace DotNetCore.CAP.EntityFrameworkCore +{ + public class FetchedMessage + { + public string MessageId { get; set; } + } +} diff --git a/src/DotNetCore.CAP/IFetchedMessage.cs b/src/DotNetCore.CAP/IFetchedMessage.cs new file mode 100644 index 0000000..b1c8b76 --- /dev/null +++ b/src/DotNetCore.CAP/IFetchedMessage.cs @@ -0,0 +1,13 @@ +using System; + +namespace DotNetCore.CAP +{ + public interface IFetchedMessage : IDisposable + { + int MessageId { get; } + + void RemoveFromQueue(); + + void Requeue(); + } +} diff --git a/src/DotNetCore.CAP/IStorage.cs b/src/DotNetCore.CAP/IStorage.cs new file mode 100644 index 0000000..1140411 --- /dev/null +++ b/src/DotNetCore.CAP/IStorage.cs @@ -0,0 +1,16 @@ +using System.Threading; +using System.Threading.Tasks; + +namespace DotNetCore.CAP +{ + /// + /// Represents a persisted storage. + /// + public interface IStorage + { + /// + /// Initializes the storage. For example, making sure a database is created and migrations are applied. + /// + Task InitializeAsync(CancellationToken cancellationToken); + } +} diff --git a/src/DotNetCore.CAP/IStorageConnection.cs b/src/DotNetCore.CAP/IStorageConnection.cs new file mode 100644 index 0000000..da81af6 --- /dev/null +++ b/src/DotNetCore.CAP/IStorageConnection.cs @@ -0,0 +1,68 @@ +using System; +using System.Threading.Tasks; +using DotNetCore.CAP.Models; + +namespace DotNetCore.CAP +{ + /// + /// Represents a connection to the storage. + /// + public interface IStorageConnection : IDisposable + { + + //Sent messages + + /// + /// Stores the message. + /// + /// The message to store. + Task StoreSentMessageAsync(CapSentMessage message); + + /// + /// Returns the message with the given id. + /// + /// The message's id. + Task GetSentMessageAsync(string id); + + /// + /// Fetches the next message to be executed. + /// + Task FetchNextSentMessageAsync(); + + /// + /// Returns the next message to be enqueued. + /// + Task GetNextSentMessageToBeEnqueuedAsync(); + + // Received messages + + /// + /// Stores the message. + /// + /// The message to store. + Task StoreReceivedMessageAsync(CapReceivedMessage message); + + /// + /// Returns the message with the given id. + /// + /// The message's id. + Task GetReceivedMessageAsync(string id); + + /// + /// Fetches the next message to be executed. + /// + Task FetchNextReceivedMessageAsync(); + + /// + /// Returns the next message to be enqueued. + /// + Task GetNextReceviedMessageToBeEnqueuedAsync(); + + //----------------------------------------- + + /// + /// Creates and returns an . + /// + IStorageTransaction CreateTransaction(); + } +} diff --git a/src/DotNetCore.CAP/IStorageTransaction.cs b/src/DotNetCore.CAP/IStorageTransaction.cs new file mode 100644 index 0000000..7aaf6e1 --- /dev/null +++ b/src/DotNetCore.CAP/IStorageTransaction.cs @@ -0,0 +1,19 @@ +using System; +using System.Threading.Tasks; +using DotNetCore.CAP.Models; + +namespace DotNetCore.CAP +{ + public interface IStorageTransaction : IDisposable + { + void UpdateMessage(CapSentMessage message); + + void UpdateMessage(CapReceivedMessage message); + + void EnqueueMessage(CapSentMessage message); + + void EnqueueMessage(CapReceivedMessage message); + + Task CommitAsync(); + } +} diff --git a/src/DotNetCore.CAP/Infrastructure/CapReceivedMessage.cs b/src/DotNetCore.CAP/Models/CapReceivedMessage.cs similarity index 96% rename from src/DotNetCore.CAP/Infrastructure/CapReceivedMessage.cs rename to src/DotNetCore.CAP/Models/CapReceivedMessage.cs index 7ca0525..09878a7 100644 --- a/src/DotNetCore.CAP/Infrastructure/CapReceivedMessage.cs +++ b/src/DotNetCore.CAP/Models/CapReceivedMessage.cs @@ -1,6 +1,6 @@ using System; -namespace DotNetCore.CAP.Infrastructure +namespace DotNetCore.CAP.Models { public class CapReceivedMessage { diff --git a/src/DotNetCore.CAP/Infrastructure/CapSentMessage.cs b/src/DotNetCore.CAP/Models/CapSentMessage.cs similarity index 90% rename from src/DotNetCore.CAP/Infrastructure/CapSentMessage.cs rename to src/DotNetCore.CAP/Models/CapSentMessage.cs index c250a48..5d088ae 100644 --- a/src/DotNetCore.CAP/Infrastructure/CapSentMessage.cs +++ b/src/DotNetCore.CAP/Models/CapSentMessage.cs @@ -1,6 +1,6 @@ using System; -namespace DotNetCore.CAP.Infrastructure +namespace DotNetCore.CAP.Models { public class CapSentMessage { @@ -30,7 +30,7 @@ namespace DotNetCore.CAP.Infrastructure public DateTime Added { get; set; } - public DateTime LastRun { get; set; } + public DateTime? LastRun { get; set; } public int Retries { get; set; } From 20b90339d77b13ec6a26e9c5c9b5f2822f93df93 Mon Sep 17 00:00:00 2001 From: yangxiaodong Date: Tue, 11 Jul 2017 15:40:01 +0800 Subject: [PATCH 02/68] Refactor message storage. --- .../CAP.BuilderExtensions.cs | 5 +- .../CapDbContext.cs | 25 ++- .../CapMessageStore.cs | 1 + .../EFFetchedMessage.cs | 70 ++++++++ .../EFStorageConnection.cs | 170 +++++------------- .../EFStorageTransaction.cs | 68 ++++--- .../HelperExtensions.cs | 30 ++++ src/DotNetCore.CAP/ICapMessageStore.cs | 1 + src/DotNetCore.CAP/ICapPublisher.Default.cs | 1 + .../IConsumerHandler.Default.cs | 1 + src/DotNetCore.CAP/IFetchedMessage.cs | 2 +- src/DotNetCore.CAP/Models/CapQueue.cs | 14 ++ .../Models/CapReceivedMessage.cs | 3 +- src/DotNetCore.CAP/Models/CapSentMessage.cs | 1 + .../EFMessageStoreTest.cs | 1 + test/DotNetCore.CAP.Test/CAP.BuilderTest.cs | 2 +- test/DotNetCore.CAP.Test/NoopMessageStore.cs | 1 + test/Shared/MessageManagerTestBase.cs | 1 + 18 files changed, 230 insertions(+), 167 deletions(-) create mode 100644 src/DotNetCore.CAP.EntityFrameworkCore/EFFetchedMessage.cs create mode 100644 src/DotNetCore.CAP.EntityFrameworkCore/HelperExtensions.cs create mode 100644 src/DotNetCore.CAP/Models/CapQueue.cs diff --git a/src/DotNetCore.CAP.EntityFrameworkCore/CAP.BuilderExtensions.cs b/src/DotNetCore.CAP.EntityFrameworkCore/CAP.BuilderExtensions.cs index 5cd1553..d7bc4d3 100644 --- a/src/DotNetCore.CAP.EntityFrameworkCore/CAP.BuilderExtensions.cs +++ b/src/DotNetCore.CAP.EntityFrameworkCore/CAP.BuilderExtensions.cs @@ -21,7 +21,7 @@ namespace Microsoft.Extensions.DependencyInjection builder.Services.AddScoped>(); builder.Services.AddScoped(); - builder.Services.AddScoped>(); + builder.Services.AddScoped(); return builder; } @@ -30,10 +30,11 @@ namespace Microsoft.Extensions.DependencyInjection public static CapBuilder AddEntityFrameworkStores(this CapBuilder builder, Action options) where TContext : DbContext { + builder.Services.AddScoped>(); builder.Services.AddScoped(); - builder.Services.AddScoped>(); + builder.Services.AddScoped(); builder.Services.Configure(options); return builder; diff --git a/src/DotNetCore.CAP.EntityFrameworkCore/CapDbContext.cs b/src/DotNetCore.CAP.EntityFrameworkCore/CapDbContext.cs index 829a2fb..b255f1d 100644 --- a/src/DotNetCore.CAP.EntityFrameworkCore/CapDbContext.cs +++ b/src/DotNetCore.CAP.EntityFrameworkCore/CapDbContext.cs @@ -1,4 +1,6 @@ -using DotNetCore.CAP.Infrastructure; +using System.Data.Common; +using DotNetCore.CAP.Infrastructure; +using DotNetCore.CAP.Models; using Microsoft.EntityFrameworkCore; namespace DotNetCore.CAP.EntityFrameworkCore @@ -8,6 +10,8 @@ namespace DotNetCore.CAP.EntityFrameworkCore /// public class CapDbContext : DbContext { + private readonly EFOptions _efOptions; + /// /// Initializes a new instance of the . /// @@ -17,18 +21,26 @@ namespace DotNetCore.CAP.EntityFrameworkCore /// Initializes a new instance of the . /// /// The options to be used by a . - public CapDbContext(DbContextOptions options) : base(options) { } + public CapDbContext(DbContextOptions options, EFOptions efOptions) + : base(options) { + _efOptions = efOptions; + } /// /// Gets or sets the of Messages. /// public DbSet CapSentMessages { get; set; } + + public DbSet CapQueue { get; set; } + /// /// Gets or sets the of Messages. /// public DbSet CapReceivedMessages { get; set; } + public DbConnection GetDbConnection() => Database.GetDbConnection(); + /// /// Configures the schema for the identity framework. /// @@ -37,15 +49,20 @@ namespace DotNetCore.CAP.EntityFrameworkCore /// protected override void OnModelCreating(ModelBuilder modelBuilder) { + modelBuilder.HasDefaultSchema(_efOptions.Schema); + modelBuilder.Entity(b => { b.HasKey(m => m.Id); - b.Property(p => p.StatusName).HasMaxLength(50); + b.HasIndex(x => x.StatusName); + b.Property(p => p.StatusName).IsRequired().HasMaxLength(50); }); modelBuilder.Entity(b => { - b.Property(p => p.StatusName).HasMaxLength(50); + b.HasKey(m => m.Id); + b.HasIndex(x => x.StatusName); + b.Property(p => p.StatusName).IsRequired().HasMaxLength(50); }); } } diff --git a/src/DotNetCore.CAP.EntityFrameworkCore/CapMessageStore.cs b/src/DotNetCore.CAP.EntityFrameworkCore/CapMessageStore.cs index bc3fedf..24bf796 100644 --- a/src/DotNetCore.CAP.EntityFrameworkCore/CapMessageStore.cs +++ b/src/DotNetCore.CAP.EntityFrameworkCore/CapMessageStore.cs @@ -1,6 +1,7 @@ using System; using System.Threading.Tasks; using DotNetCore.CAP.Infrastructure; +using DotNetCore.CAP.Models; using Microsoft.EntityFrameworkCore; namespace DotNetCore.CAP.EntityFrameworkCore diff --git a/src/DotNetCore.CAP.EntityFrameworkCore/EFFetchedMessage.cs b/src/DotNetCore.CAP.EntityFrameworkCore/EFFetchedMessage.cs new file mode 100644 index 0000000..171b8dd --- /dev/null +++ b/src/DotNetCore.CAP.EntityFrameworkCore/EFFetchedMessage.cs @@ -0,0 +1,70 @@ +using System; +using System.Collections.Generic; +using System.Data; +using System.Text; +using System.Threading; +using Microsoft.EntityFrameworkCore.Storage; + +namespace DotNetCore.CAP.EntityFrameworkCore +{ + public class EFFetchedMessage : IFetchedMessage + { + private readonly IDbConnection _connection; + private readonly IDbContextTransaction _transaction; + private readonly Timer _timer; + private static readonly TimeSpan KeepAliveInterval = TimeSpan.FromMinutes(1); + private readonly object _lockObject = new object(); + + public EFFetchedMessage(string messageId, + IDbConnection connection, + IDbContextTransaction transaction) + { + MessageId = messageId; + _connection = connection; + _transaction = transaction; + _timer = new Timer(ExecuteKeepAliveQuery, null, KeepAliveInterval, KeepAliveInterval); + } + + public string MessageId { get; } + + public void RemoveFromQueue() + { + lock (_lockObject) + { + _transaction.Commit(); + } + } + + public void Requeue() + { + lock (_lockObject) + { + _transaction.Rollback(); + } + } + + public void Dispose() + { + lock (_lockObject) + { + _timer?.Dispose(); + _transaction.Dispose(); + _connection.Dispose(); + } + } + + private void ExecuteKeepAliveQuery(object obj) + { + lock (_lockObject) + { + try + { + _connection?.Execute("SELECT 1", _transaction.GetDbTransaction()); + } + catch + { + } + } + } + } +} diff --git a/src/DotNetCore.CAP.EntityFrameworkCore/EFStorageConnection.cs b/src/DotNetCore.CAP.EntityFrameworkCore/EFStorageConnection.cs index 257f682..3026424 100644 --- a/src/DotNetCore.CAP.EntityFrameworkCore/EFStorageConnection.cs +++ b/src/DotNetCore.CAP.EntityFrameworkCore/EFStorageConnection.cs @@ -1,20 +1,15 @@ using System; using System.Data; -using System.Data.SqlClient; using System.Linq; using System.Threading.Tasks; -using Dapper; +using DotNetCore.CAP.Infrastructure; using DotNetCore.CAP.Models; using Microsoft.EntityFrameworkCore; -using Microsoft.EntityFrameworkCore.Storage; using Microsoft.Extensions.Options; -using MR.AspNetCore.Jobs.Models; -using MR.AspNetCore.Jobs.Server; -using MR.AspNetCore.Jobs.Server.States; namespace DotNetCore.CAP.EntityFrameworkCore { - public class EFStorageConnection : IStorageConnection where TContext : DbContext + public class EFStorageConnection : IStorageConnection { private readonly CapDbContext _context; private readonly EFOptions _options; @@ -31,67 +26,11 @@ namespace DotNetCore.CAP.EntityFrameworkCore public EFOptions Options => _options; - - - public Task StoreCronJobAsync(CronJob job) - { - if (job == null) throw new ArgumentNullException(nameof(job)); - - _context.Add(job); - return _context.SaveChangesAsync(); - } - - public Task AttachCronJobAsync(CronJob job) - { - if (job == null) throw new ArgumentNullException(nameof(job)); - - _context.Attach(job); - return Task.FromResult(true); - } - - public Task UpdateCronJobAsync(CronJob job) - { - if (job == null) throw new ArgumentNullException(nameof(job)); - - return _context.SaveChangesAsync(); - } - - public Task GetCronJobsAsync() - { - return _context.CronJobs.ToArrayAsync(); - } - - public async Task RemoveCronJobAsync(string name) - { - var cronJob = await _context.CronJobs.FirstOrDefaultAsync(j => j.Name == name); - if (cronJob != null) - { - _context.Remove(cronJob); - await _context.SaveChangesAsync(); - } - } - public IStorageTransaction CreateTransaction() { return new EFStorageTransaction(this); } - public void Dispose() - { - } - - private DateTime? NormalizeDateTime(DateTime? dateTime) - { - if (!dateTime.HasValue) return dateTime; - if (dateTime == DateTime.MinValue) - { - return new DateTime(1754, 1, 1, 0, 0, 0, DateTimeKind.Utc); - } - return dateTime; - } - - - public Task StoreSentMessageAsync(CapSentMessage message) { if (message == null) throw new ArgumentNullException(nameof(message)); @@ -107,96 +46,83 @@ namespace DotNetCore.CAP.EntityFrameworkCore return _context.CapSentMessages.FirstOrDefaultAsync(x => x.Id == id); } - public Task FetchNextJobAsync() + public async Task FetchNextSentMessageAsync() { - + // var sql = $@" + //DELETE TOP (1) + //FROM [{_options.Schema}].[{nameof(CapDbContext.CapSentMessages)}] WITH (readpast, updlock, rowlock) + //OUTPUT DELETED.Id"; + + var queueFirst = await _context.CapQueue.FirstOrDefaultAsync(); + if (queueFirst == null) + return null; + + _context.CapQueue.Remove(queueFirst); + + var connection = _context.Database.GetDbConnection(); + var transaction = _context.Database.CurrentTransaction; + transaction = transaction ?? await _context.Database.BeginTransactionAsync(IsolationLevel.ReadCommitted); + return new EFFetchedMessage(queueFirst.MessageId, connection, transaction); } - public async Task GetNextJobToBeEnqueuedAsync() + public Task GetNextSentMessageToBeEnqueuedAsync() { - var sql = $@" -SELECT TOP (1) * -FROM [{_options.Schema}].[{nameof(JobsDbContext.Jobs)}] WITH (readpast) -WHERE (Due IS NULL OR Due < GETUTCDATE()) AND StateName = '{ScheduledState.StateName}'"; + // var sql = $@" + //SELECT TOP (1) * + //FROM [{_options.Schema}].[{nameof(CapDbContext.CapSentMessages)}] WITH (readpast) + //WHERE (Due IS NULL OR Due < GETUTCDATE()) AND StateName = '{StatusName.Enqueued}'"; - var connection = _context.GetDbConnection(); + // var connection = _context.GetDbConnection(); - var job = (await connection.QueryAsync(sql)).FirstOrDefault(); + // var message = _context.CapSentMessages.FromSql(sql).FirstOrDefaultAsync(); - if (job != null) + var message = _context.CapSentMessages.Where(x => x.StatusName == StatusName.Enqueued).FirstOrDefaultAsync(); + + if (message != null) { - _context.Attach(job); + _context.Attach(message); } - return job; + return message; } - public Task FetchNextSentMessageAsync() + public Task StoreReceivedMessageAsync(CapReceivedMessage message) { - var sql = $@" -DELETE TOP (1) -FROM [{_options.Schema}].[{nameof(CapDbContext.CapSentMessages)}] WITH (readpast, updlock, rowlock) -OUTPUT DELETED.Id"; + if (message == null) throw new ArgumentNullException(nameof(message)); - //return FetchNextDelayedMessageCoreAsync(sql); - throw new NotImplementedException(); - } + message.LastRun = NormalizeDateTime(message.LastRun); - //private async Task FetchNextDelayedMessageCoreAsync(string sql, object args = null) - //{ - // FetchedMessage fetchedJob = null; - // var connection = _context.Database.GetDbConnection(); - // var transaction = _context.Database.CurrentTransaction; - // transaction = transaction ?? await _context.Database.BeginTransactionAsync(IsolationLevel.ReadCommitted); - - // try - // { - // fetchedJob = - // (await _context...QueryAsync(sql, args, transaction.GetDbTransaction())) - // .FirstOrDefault(); - // } - // catch (SqlException) - // { - // transaction.Dispose(); - // throw; - // } - - // if (fetchedJob == null) - // { - // transaction.Rollback(); - // transaction.Dispose(); - // return null; - // } - - // return new SqlServerFetchedJob( - // fetchedJob.JobId, - // connection, - // transaction); - //} + _context.Add(message); + return _context.SaveChangesAsync(); + } - public Task GetNextSentMessageToBeEnqueuedAsync() + public Task GetReceivedMessageAsync(string id) { - throw new NotImplementedException(); + return _context.CapReceivedMessages.FirstOrDefaultAsync(x => x.Id == id); } - public Task StoreReceivedMessageAsync(CapReceivedMessage message) + public Task FetchNextReceivedMessageAsync() { throw new NotImplementedException(); } - public Task GetReceivedMessageAsync(string id) + public Task GetNextReceviedMessageToBeEnqueuedAsync() { throw new NotImplementedException(); } - public Task FetchNextReceivedMessageAsync() + private DateTime? NormalizeDateTime(DateTime? dateTime) { - throw new NotImplementedException(); + if (!dateTime.HasValue) return dateTime; + if (dateTime == DateTime.MinValue) + { + return new DateTime(1754, 1, 1, 0, 0, 0, DateTimeKind.Utc); + } + return dateTime; } - public Task GetNextReceviedMessageToBeEnqueuedAsync() + public void Dispose() { - throw new NotImplementedException(); } } } diff --git a/src/DotNetCore.CAP.EntityFrameworkCore/EFStorageTransaction.cs b/src/DotNetCore.CAP.EntityFrameworkCore/EFStorageTransaction.cs index d511d6a..47cb24c 100644 --- a/src/DotNetCore.CAP.EntityFrameworkCore/EFStorageTransaction.cs +++ b/src/DotNetCore.CAP.EntityFrameworkCore/EFStorageTransaction.cs @@ -4,64 +4,60 @@ using DotNetCore.CAP.Models; namespace DotNetCore.CAP.EntityFrameworkCore { - public class EFStorageTransaction : IStorageTransaction, IDisposable - { - private EFStorageConnection _connection; + public class EFStorageTransaction + : IStorageTransaction, IDisposable + { + private EFStorageConnection _connection; - public EFStorageTransaction(EFStorageConnection connection) - { - _connection = connection; - } - - public void UpdateJob(Job job) - { - if (job == null) throw new ArgumentNullException(nameof(job)); - - // NOOP. EF will detect changes. - } - - public void EnqueueJob(Job job) - { - - } - - public Task CommitAsync() - { - return _connection.Context.SaveChangesAsync(); - } - - public void Dispose() - { - } + public EFStorageTransaction(EFStorageConnection connection) + { + _connection = connection; + } public void UpdateMessage(CapSentMessage message) { - throw new NotImplementedException(); + if (message == null) throw new ArgumentNullException(nameof(message)); + + // NOOP. EF will detect changes. } public void UpdateMessage(CapReceivedMessage message) { - throw new NotImplementedException(); + if (message == null) throw new ArgumentNullException(nameof(message)); + + // NOOP. EF will detect changes. } public void EnqueueMessage(CapSentMessage message) { - if (job == null) throw new ArgumentNullException(nameof(job)); + if (message == null) throw new ArgumentNullException(nameof(message)); - _connection.Context.Add(new JobQueue + _connection.Context.Add(new CapQueue { - JobId = job.Id + MessageId = message.Id, + Type = 0 }); } public void EnqueueMessage(CapReceivedMessage message) { - if (job == null) throw new ArgumentNullException(nameof(job)); + if (message == null) throw new ArgumentNullException(nameof(message)); - _connection.Context.Add(new JobQueue + _connection.Context.Add(new CapQueue { - JobId = job.Id + MessageId = message.Id, + Type = 1 }); } + + + public Task CommitAsync() + { + return _connection.Context.SaveChangesAsync(); + } + + public void Dispose() + { + } } } diff --git a/src/DotNetCore.CAP.EntityFrameworkCore/HelperExtensions.cs b/src/DotNetCore.CAP.EntityFrameworkCore/HelperExtensions.cs new file mode 100644 index 0000000..02342d6 --- /dev/null +++ b/src/DotNetCore.CAP.EntityFrameworkCore/HelperExtensions.cs @@ -0,0 +1,30 @@ +using System; +using System.Collections.Generic; +using System.Data; + +namespace DotNetCore.CAP.EntityFrameworkCore +{ + static class HelperExtensions + { + public static void Execute(this IDbConnection connection, string sql, IDbTransaction transcation = null) + { + try + { + connection.Open(); + using (var command = connection.CreateCommand()) + { + command.CommandText = "SELELCT 1"; + if (transcation != null) + command.Transaction = transcation; + command.ExecuteNonQuery(); + } + } + finally + { + connection.Close(); + } + } + + + } +} \ No newline at end of file diff --git a/src/DotNetCore.CAP/ICapMessageStore.cs b/src/DotNetCore.CAP/ICapMessageStore.cs index 4440a6a..958a749 100644 --- a/src/DotNetCore.CAP/ICapMessageStore.cs +++ b/src/DotNetCore.CAP/ICapMessageStore.cs @@ -1,5 +1,6 @@ using System.Threading.Tasks; using DotNetCore.CAP.Infrastructure; +using DotNetCore.CAP.Models; namespace DotNetCore.CAP { diff --git a/src/DotNetCore.CAP/ICapPublisher.Default.cs b/src/DotNetCore.CAP/ICapPublisher.Default.cs index 454e6e5..334ce87 100644 --- a/src/DotNetCore.CAP/ICapPublisher.Default.cs +++ b/src/DotNetCore.CAP/ICapPublisher.Default.cs @@ -1,6 +1,7 @@ using System; using System.Threading.Tasks; using DotNetCore.CAP.Infrastructure; +using DotNetCore.CAP.Models; using Microsoft.Extensions.Logging; namespace DotNetCore.CAP diff --git a/src/DotNetCore.CAP/IConsumerHandler.Default.cs b/src/DotNetCore.CAP/IConsumerHandler.Default.cs index aebf720..cf2936a 100644 --- a/src/DotNetCore.CAP/IConsumerHandler.Default.cs +++ b/src/DotNetCore.CAP/IConsumerHandler.Default.cs @@ -5,6 +5,7 @@ using System.Threading.Tasks; using DotNetCore.CAP.Abstractions; using DotNetCore.CAP.Infrastructure; using DotNetCore.CAP.Internal; +using DotNetCore.CAP.Models; using Microsoft.Extensions.DependencyInjection; using Microsoft.Extensions.Logging; using Microsoft.Extensions.Options; diff --git a/src/DotNetCore.CAP/IFetchedMessage.cs b/src/DotNetCore.CAP/IFetchedMessage.cs index b1c8b76..2dc2f68 100644 --- a/src/DotNetCore.CAP/IFetchedMessage.cs +++ b/src/DotNetCore.CAP/IFetchedMessage.cs @@ -4,7 +4,7 @@ namespace DotNetCore.CAP { public interface IFetchedMessage : IDisposable { - int MessageId { get; } + string MessageId { get; } void RemoveFromQueue(); diff --git a/src/DotNetCore.CAP/Models/CapQueue.cs b/src/DotNetCore.CAP/Models/CapQueue.cs new file mode 100644 index 0000000..bb64de1 --- /dev/null +++ b/src/DotNetCore.CAP/Models/CapQueue.cs @@ -0,0 +1,14 @@ +namespace DotNetCore.CAP.Models +{ + public class CapQueue + { + public int Id { get; set; } + + public string MessageId { get; set; } + + /// + /// 0 is CapSentMessage, 1 is CapReceviedMessage + /// + public int Type { get; set; } + } +} diff --git a/src/DotNetCore.CAP/Models/CapReceivedMessage.cs b/src/DotNetCore.CAP/Models/CapReceivedMessage.cs index 09878a7..ce1df51 100644 --- a/src/DotNetCore.CAP/Models/CapReceivedMessage.cs +++ b/src/DotNetCore.CAP/Models/CapReceivedMessage.cs @@ -1,4 +1,5 @@ using System; +using DotNetCore.CAP.Infrastructure; namespace DotNetCore.CAP.Models { @@ -33,7 +34,7 @@ namespace DotNetCore.CAP.Models public DateTime Added { get; set; } - public DateTime LastRun { get; set; } + public DateTime? LastRun { get; set; } public int Retries { get; set; } diff --git a/src/DotNetCore.CAP/Models/CapSentMessage.cs b/src/DotNetCore.CAP/Models/CapSentMessage.cs index 5d088ae..f615fa7 100644 --- a/src/DotNetCore.CAP/Models/CapSentMessage.cs +++ b/src/DotNetCore.CAP/Models/CapSentMessage.cs @@ -1,4 +1,5 @@ using System; +using DotNetCore.CAP.Infrastructure; namespace DotNetCore.CAP.Models { diff --git a/test/DotNetCore.CAP.EntityFrameworkCore.Test/EFMessageStoreTest.cs b/test/DotNetCore.CAP.EntityFrameworkCore.Test/EFMessageStoreTest.cs index c138173..2897482 100644 --- a/test/DotNetCore.CAP.EntityFrameworkCore.Test/EFMessageStoreTest.cs +++ b/test/DotNetCore.CAP.EntityFrameworkCore.Test/EFMessageStoreTest.cs @@ -1,6 +1,7 @@ using System; using System.Linq; using DotNetCore.CAP.Infrastructure; +using DotNetCore.CAP.Models; using Microsoft.Extensions.DependencyInjection; using Xunit; diff --git a/test/DotNetCore.CAP.Test/CAP.BuilderTest.cs b/test/DotNetCore.CAP.Test/CAP.BuilderTest.cs index d526c75..e4810fd 100644 --- a/test/DotNetCore.CAP.Test/CAP.BuilderTest.cs +++ b/test/DotNetCore.CAP.Test/CAP.BuilderTest.cs @@ -1,8 +1,8 @@ using System; using System.Threading; using System.Threading.Tasks; -using DotNetCore.CAP.Infrastructure; using DotNetCore.CAP.Job; +using DotNetCore.CAP.Models; using Microsoft.Extensions.DependencyInjection; using Xunit; diff --git a/test/DotNetCore.CAP.Test/NoopMessageStore.cs b/test/DotNetCore.CAP.Test/NoopMessageStore.cs index 7100a21..dfa7be4 100644 --- a/test/DotNetCore.CAP.Test/NoopMessageStore.cs +++ b/test/DotNetCore.CAP.Test/NoopMessageStore.cs @@ -2,6 +2,7 @@ using System.Threading; using System.Threading.Tasks; using DotNetCore.CAP.Infrastructure; +using DotNetCore.CAP.Models; namespace DotNetCore.CAP.Test { diff --git a/test/Shared/MessageManagerTestBase.cs b/test/Shared/MessageManagerTestBase.cs index 0f981e2..f375bf2 100644 --- a/test/Shared/MessageManagerTestBase.cs +++ b/test/Shared/MessageManagerTestBase.cs @@ -1,6 +1,7 @@ using System; using System.Threading.Tasks; using DotNetCore.CAP.Infrastructure; +using DotNetCore.CAP.Models; using Microsoft.AspNetCore.Http; using Microsoft.Extensions.DependencyInjection; using Microsoft.Extensions.Logging; From c61ae1516b646571be12406517df6ada151b826c Mon Sep 17 00:00:00 2001 From: yangxiaodong Date: Tue, 11 Jul 2017 18:53:52 +0800 Subject: [PATCH 03/68] refactor storage --- .../CAP.BuilderExtensions.cs | 21 ++- .../CAP.EFOptions.cs | 18 ++ .../CapMessageStore.cs | 156 ------------------ .../DotNetCore.CAP.EntityFrameworkCore.csproj | 4 + .../EFStorageConnection.cs | 12 +- .../IProcessor.RabbitJobProcessor.cs | 128 ++++++++++---- src/DotNetCore.CAP/ICapMessageStore.cs | 57 ------- .../IConsumerHandler.Default.cs | 8 +- src/DotNetCore.CAP/IStorageConnection.cs | 10 +- .../Job/IJobProcessor.JobQueuer.cs | 65 ++++++++ .../Job/States/IState.Enqueued.cs | 24 +++ .../Job/States/IState.Failed.cs | 22 +++ .../Job/States/IState.Processing.cs | 22 +++ .../Job/States/IState.Scheduled.cs | 22 +++ .../Job/States/IState.Succeeded.cs | 22 +++ src/DotNetCore.CAP/Job/States/IState.cs | 16 ++ .../Job/States/IStateChanger.Default.cs | 41 +++++ .../Job/States/IStateChanger.Extensions.cs | 28 ++++ .../Job/States/IStateChanger.cs | 11 ++ src/DotNetCore.CAP/OperateResult.cs | 16 +- 20 files changed, 433 insertions(+), 270 deletions(-) create mode 100644 src/DotNetCore.CAP/Job/IJobProcessor.JobQueuer.cs create mode 100644 src/DotNetCore.CAP/Job/States/IState.Enqueued.cs create mode 100644 src/DotNetCore.CAP/Job/States/IState.Failed.cs create mode 100644 src/DotNetCore.CAP/Job/States/IState.Processing.cs create mode 100644 src/DotNetCore.CAP/Job/States/IState.Scheduled.cs create mode 100644 src/DotNetCore.CAP/Job/States/IState.Succeeded.cs create mode 100644 src/DotNetCore.CAP/Job/States/IState.cs create mode 100644 src/DotNetCore.CAP/Job/States/IStateChanger.Default.cs create mode 100644 src/DotNetCore.CAP/Job/States/IStateChanger.Extensions.cs create mode 100644 src/DotNetCore.CAP/Job/States/IStateChanger.cs diff --git a/src/DotNetCore.CAP.EntityFrameworkCore/CAP.BuilderExtensions.cs b/src/DotNetCore.CAP.EntityFrameworkCore/CAP.BuilderExtensions.cs index d7bc4d3..c6c0831 100644 --- a/src/DotNetCore.CAP.EntityFrameworkCore/CAP.BuilderExtensions.cs +++ b/src/DotNetCore.CAP.EntityFrameworkCore/CAP.BuilderExtensions.cs @@ -19,7 +19,6 @@ namespace Microsoft.Extensions.DependencyInjection where TContext : DbContext { builder.Services.AddScoped>(); - builder.Services.AddScoped(); builder.Services.AddScoped(); @@ -27,15 +26,27 @@ namespace Microsoft.Extensions.DependencyInjection } - public static CapBuilder AddEntityFrameworkStores(this CapBuilder builder, Action options) + public static CapBuilder AddEntityFrameworkStores(this CapBuilder builder, Action actionOptions) where TContext : DbContext { builder.Services.AddScoped>(); - - builder.Services.AddScoped(); + builder.Services.AddSingleton(); builder.Services.AddScoped(); - builder.Services.Configure(options); + builder.Services.Configure(actionOptions); + + var efOptions = new EFOptions(); + actionOptions(efOptions); + + builder.Services.AddDbContext(options => + { + options.UseSqlServer(efOptions.ConnectionString, sqlOpts => + { + sqlOpts.MigrationsHistoryTable( + efOptions.MigrationsHistoryTableName, + efOptions.MigrationsHistoryTableSchema ?? efOptions.Schema); + }); + }); return builder; } diff --git a/src/DotNetCore.CAP.EntityFrameworkCore/CAP.EFOptions.cs b/src/DotNetCore.CAP.EntityFrameworkCore/CAP.EFOptions.cs index cdb877b..b019803 100644 --- a/src/DotNetCore.CAP.EntityFrameworkCore/CAP.EFOptions.cs +++ b/src/DotNetCore.CAP.EntityFrameworkCore/CAP.EFOptions.cs @@ -7,11 +7,29 @@ namespace DotNetCore.CAP.EntityFrameworkCore public class EFOptions { public const string DefaultSchema = "cap"; + public const string DefaultMigrationsHistoryTableName = "__EFMigrationsHistory"; + + /// + /// Gets or sets the database's connection string that will be used to store database entities. + /// + public string ConnectionString { get; set; } /// /// Gets or sets the schema to use when creating database objects. /// Default is . /// public string Schema { get; set; } = DefaultSchema; + + /// + /// Gets or sets the migrations history table's schema. + /// If this is null, will be used. + /// + public string MigrationsHistoryTableSchema { get; set; } + + /// + /// Gets or sets the migrations history table's name. + /// Default is . + /// + public string MigrationsHistoryTableName { get; set; } = DefaultMigrationsHistoryTableName; } } diff --git a/src/DotNetCore.CAP.EntityFrameworkCore/CapMessageStore.cs b/src/DotNetCore.CAP.EntityFrameworkCore/CapMessageStore.cs index 24bf796..ee078d5 100644 --- a/src/DotNetCore.CAP.EntityFrameworkCore/CapMessageStore.cs +++ b/src/DotNetCore.CAP.EntityFrameworkCore/CapMessageStore.cs @@ -1,6 +1,5 @@ using System; using System.Threading.Tasks; -using DotNetCore.CAP.Infrastructure; using DotNetCore.CAP.Models; using Microsoft.EntityFrameworkCore; @@ -25,8 +24,6 @@ namespace DotNetCore.CAP.EntityFrameworkCore private DbSet SentMessages => Context.Set(); - private DbSet ReceivedMessages => Context.Set(); - /// /// Creates the specified in the cap message store. /// @@ -39,158 +36,5 @@ namespace DotNetCore.CAP.EntityFrameworkCore await Context.SaveChangesAsync(); return OperateResult.Success; } - - public async Task ChangeSentMessageStateAsync(CapSentMessage message, string status, - bool autoSaveChanges = true) - { - Context.Attach(message); - message.LastRun = DateTime.Now; - message.StatusName = status; - try - { - if (autoSaveChanges) - { - await Context.SaveChangesAsync(); - } - } - catch (DbUpdateConcurrencyException ex) - { - return OperateResult.Failed( - new OperateError() - { - Code = "DbUpdateConcurrencyException", - Description = ex.Message - }); - } - return OperateResult.Success; - } - - /// - /// First Enqueued Message. - /// - public async Task GetNextSentMessageToBeEnqueuedAsync() - { - return await SentMessages.FirstOrDefaultAsync(x => x.StatusName == StatusName.Enqueued); - } - - /// - /// Updates a message in a store as an asynchronous operation. - /// - /// The message to update in the store. - public async Task UpdateSentMessageAsync(CapSentMessage message) - { - if (message == null) throw new ArgumentNullException(nameof(message)); - - Context.Attach(message); - message.LastRun = DateTime.Now; - Context.Update(message); - - try - { - await Context.SaveChangesAsync(); - return OperateResult.Success; - } - catch (DbUpdateConcurrencyException ex) - { - return OperateResult.Failed(new OperateError() - { - Code = "DbUpdateConcurrencyException", - Description = ex.Message - }); - } - } - - /// - /// Deletes the specified from the consistency message store. - /// - /// The message to delete. - public async Task RemoveSentMessageAsync(CapSentMessage message) - { - if (message == null) throw new ArgumentNullException(nameof(message)); - - Context.Remove(message); - try - { - await Context.SaveChangesAsync(); - return OperateResult.Success; - } - catch (DbUpdateConcurrencyException ex) - { - return OperateResult.Failed(new OperateError() - { - Code = "DbUpdateConcurrencyException", - Description = ex.Message - }); - } - } - - /// - /// Creates the specified in the consistency message store. - /// - /// The message to create. - public async Task StoreReceivedMessageAsync(CapReceivedMessage message) - { - if (message == null) throw new ArgumentNullException(nameof(message)); - - Context.Add(message); - await Context.SaveChangesAsync(); - return OperateResult.Success; - } - - public async Task ChangeReceivedMessageStateAsync(CapReceivedMessage message, string status, - bool autoSaveChanges = true) - { - Context.Attach(message); - message.LastRun = DateTime.Now; - message.StatusName = status; - try - { - if (autoSaveChanges) - { - await Context.SaveChangesAsync(); - } - } - catch (DbUpdateConcurrencyException ex) - { - return OperateResult.Failed(new OperateError() - { - Code = "DbUpdateConcurrencyException", - Description = ex.Message - }); - } - return OperateResult.Success; - } - - public async Task GetNextReceivedMessageToBeExcuted() - { - return await ReceivedMessages.FirstOrDefaultAsync(x => x.StatusName == StatusName.Enqueued); - } - - /// - /// Updates the specified in the message store. - /// - /// The message to update. - public async Task UpdateReceivedMessageAsync(CapReceivedMessage message) - { - if (message == null) throw new ArgumentNullException(nameof(message)); - - Context.Attach(message); - message.LastRun = DateTime.Now; - Context.Update(message); - - try - { - await Context.SaveChangesAsync(); - return OperateResult.Success; - } - catch (DbUpdateConcurrencyException ex) - { - return OperateResult.Failed(new OperateError() - { - Code = "DbUpdateConcurrencyException", - Description = ex.Message - }); - } - } } } \ No newline at end of file diff --git a/src/DotNetCore.CAP.EntityFrameworkCore/DotNetCore.CAP.EntityFrameworkCore.csproj b/src/DotNetCore.CAP.EntityFrameworkCore/DotNetCore.CAP.EntityFrameworkCore.csproj index a1f9510..6a6422c 100644 --- a/src/DotNetCore.CAP.EntityFrameworkCore/DotNetCore.CAP.EntityFrameworkCore.csproj +++ b/src/DotNetCore.CAP.EntityFrameworkCore/DotNetCore.CAP.EntityFrameworkCore.csproj @@ -16,7 +16,11 @@ + + + + diff --git a/src/DotNetCore.CAP.EntityFrameworkCore/EFStorageConnection.cs b/src/DotNetCore.CAP.EntityFrameworkCore/EFStorageConnection.cs index 3026424..d0ed080 100644 --- a/src/DotNetCore.CAP.EntityFrameworkCore/EFStorageConnection.cs +++ b/src/DotNetCore.CAP.EntityFrameworkCore/EFStorageConnection.cs @@ -29,17 +29,7 @@ namespace DotNetCore.CAP.EntityFrameworkCore public IStorageTransaction CreateTransaction() { return new EFStorageTransaction(this); - } - - public Task StoreSentMessageAsync(CapSentMessage message) - { - if (message == null) throw new ArgumentNullException(nameof(message)); - - message.LastRun = NormalizeDateTime(message.LastRun); - - _context.Add(message); - return _context.SaveChangesAsync(); - } + } public Task GetSentMessageAsync(string id) { diff --git a/src/DotNetCore.CAP.RabbitMQ/IProcessor.RabbitJobProcessor.cs b/src/DotNetCore.CAP.RabbitMQ/IProcessor.RabbitJobProcessor.cs index 8534f76..f50a0a5 100644 --- a/src/DotNetCore.CAP.RabbitMQ/IProcessor.RabbitJobProcessor.cs +++ b/src/DotNetCore.CAP.RabbitMQ/IProcessor.RabbitJobProcessor.cs @@ -5,6 +5,8 @@ using System.Threading; using System.Threading.Tasks; using DotNetCore.CAP.Infrastructure; using DotNetCore.CAP.Job; +using DotNetCore.CAP.Job.States; +using DotNetCore.CAP.Models; using Microsoft.Extensions.DependencyInjection; using Microsoft.Extensions.Logging; using Microsoft.Extensions.Options; @@ -16,23 +18,26 @@ namespace DotNetCore.CAP.RabbitMQ { private readonly RabbitMQOptions _rabbitMqOptions; private readonly CancellationTokenSource _cts; - + private readonly IStateChanger _stateChanger; private readonly IServiceProvider _provider; private readonly ILogger _logger; private readonly TimeSpan _pollingDelay; + internal static readonly AutoResetEvent PulseEvent = new AutoResetEvent(true); public RabbitJobProcessor( IOptions capOptions, IOptions rabbitMQOptions, ILogger logger, + IStateChanger stateChanger, IServiceProvider provider) { _logger = logger; _rabbitMqOptions = rabbitMQOptions.Value; _provider = provider; + _stateChanger = stateChanger; _cts = new CancellationTokenSource(); - + var capOptions1 = capOptions.Value; _pollingDelay = TimeSpan.FromSeconds(capOptions1.PollingDelay); } @@ -62,7 +67,7 @@ namespace DotNetCore.CAP.RabbitMQ var token = GetTokenToWaitOn(context); } - await WaitHandleEx.WaitAnyAsync(WaitHandleEx.PulseEvent, + await WaitHandleEx.WaitAnyAsync(PulseEvent, context.CancellationToken.WaitHandle, _pollingDelay); } finally @@ -78,39 +83,93 @@ namespace DotNetCore.CAP.RabbitMQ private async Task Step(ProcessingContext context) { + var fetched = default(IFetchedMessage); using (var scopedContext = context.CreateScope()) { var provider = scopedContext.Provider; var messageStore = provider.GetRequiredService(); - var message = await messageStore.GetNextSentMessageToBeEnqueuedAsync(); - try + var connection = provider.GetRequiredService(); + + if ((fetched = await connection.FetchNextSentMessageAsync()) != null) { - if (message != null) + using (fetched) { - var sp = Stopwatch.StartNew(); - message.StatusName = StatusName.Processing; - await messageStore.UpdateSentMessageAsync(message); + var message = await connection.GetSentMessageAsync(fetched.MessageId); + try + { + var sp = Stopwatch.StartNew(); + await _stateChanger.ChangeStateAsync(message, new ProcessingState(), connection); + + if (message.Retries > 0) + { + _logger.JobRetrying(message.Retries); + } + var result = ExecuteJob(message.KeyName, message.Content); + sp.Stop(); + + var newState = default(IState); + if (!result.Succeeded) + { + var shouldRetry = await UpdateJobForRetryAsync(message, connection); + if (shouldRetry) + { + newState = new ScheduledState(); + _logger.JobFailedWillRetry(result.Exception); + } + else + { + newState = new FailedState(); + _logger.JobFailed(result.Exception); + } + } + else + { + newState = new SucceededState(); + } + await _stateChanger.ChangeStateAsync(message, newState, connection); + + fetched.RemoveFromQueue(); + + if (result.Succeeded) + { + _logger.JobExecuted(sp.Elapsed.TotalSeconds); + } + } + + catch (Exception ex) + { + _logger.ExceptionOccuredWhileExecutingJob(message?.KeyName, ex); + return false; + } - ExecuteJob(message.KeyName, message.Content); + } + } + } + return fetched != null; + } - sp.Stop(); + private async Task UpdateJobForRetryAsync(CapSentMessage message, IStorageConnection connection) + { + var retryBehavior = RetryBehavior.DefaultRetry; - message.StatusName = StatusName.Succeeded; - await messageStore.UpdateSentMessageAsync(message); + var now = DateTime.UtcNow; + var retries = ++message.Retries; + if (retries >= retryBehavior.RetryCount) + { + return false; + } - _logger.JobExecuted(sp.Elapsed.TotalSeconds); - } - } - catch (Exception ex) - { - _logger.ExceptionOccuredWhileExecutingJob(message?.KeyName, ex); - return false; - } + var due = message.Added.AddSeconds(retryBehavior.RetryIn(retries)); + message.LastRun = due; + using (var transaction = connection.CreateTransaction()) + { + transaction.UpdateMessage(message); + await transaction.CommitAsync(); } return true; } - private void ExecuteJob(string topic, string content) + private OperateResult ExecuteJob(string topic, string content) { var factory = new ConnectionFactory() { @@ -124,17 +183,26 @@ namespace DotNetCore.CAP.RabbitMQ SocketWriteTimeout = _rabbitMqOptions.SocketWriteTimeout }; - using (var connection = factory.CreateConnection()) - using (var channel = connection.CreateModel()) + try { - var body = Encoding.UTF8.GetBytes(content); + using (var connection = factory.CreateConnection()) + using (var channel = connection.CreateModel()) + { + var body = Encoding.UTF8.GetBytes(content); - channel.ExchangeDeclare(_rabbitMqOptions.TopicExchangeName, _rabbitMqOptions.EXCHANGE_TYPE); - channel.BasicPublish(exchange: _rabbitMqOptions.TopicExchangeName, - routingKey: topic, - basicProperties: null, - body: body); + channel.ExchangeDeclare(_rabbitMqOptions.TopicExchangeName, _rabbitMqOptions.EXCHANGE_TYPE); + channel.BasicPublish(exchange: _rabbitMqOptions.TopicExchangeName, + routingKey: topic, + basicProperties: null, + body: body); + } + return OperateResult.Success; + } + catch (Exception ex) + { + return OperateResult.Failed(ex, new OperateError() { Code = ex.HResult.ToString(), Description = ex.Message }); } + } } } \ No newline at end of file diff --git a/src/DotNetCore.CAP/ICapMessageStore.cs b/src/DotNetCore.CAP/ICapMessageStore.cs index 958a749..798a203 100644 --- a/src/DotNetCore.CAP/ICapMessageStore.cs +++ b/src/DotNetCore.CAP/ICapMessageStore.cs @@ -14,62 +14,5 @@ namespace DotNetCore.CAP /// /// The message to create in the store. Task StoreSentMessageAsync(CapSentMessage message); - - /// - /// Change model status name. - /// - /// The type of . - /// The status name. - /// auto save dbcontext changes. - /// - Task ChangeSentMessageStateAsync(CapSentMessage message, string statusName, - bool autoSaveChanges = true); - - /// - /// Fetches the next message to be executed. - /// - /// - Task GetNextSentMessageToBeEnqueuedAsync(); - - /// - /// Updates a message in a store as an asynchronous operation. - /// - /// The message to update in the store. - Task UpdateSentMessageAsync(CapSentMessage message); - - /// - /// Deletes a message from the store as an asynchronous operation. - /// - /// The message to delete in the store. - Task RemoveSentMessageAsync(CapSentMessage message); - - - /// - /// Creates a new message in a store as an asynchronous operation. - /// - /// - /// - Task StoreReceivedMessageAsync(CapReceivedMessage message); - - /// - /// Change model status name. - /// - /// The type of . - /// The status name. - /// auto save dbcontext changes. - /// - Task ChangeReceivedMessageStateAsync(CapReceivedMessage message, string statusName, - bool autoSaveChanges = true); - - /// - /// Fetches the next message to be executed. - /// - Task GetNextReceivedMessageToBeExcuted(); - - /// - /// Updates a message in a store as an asynchronous operation. - /// - /// The message to update in the store. - Task UpdateReceivedMessageAsync(CapReceivedMessage message); } } \ No newline at end of file diff --git a/src/DotNetCore.CAP/IConsumerHandler.Default.cs b/src/DotNetCore.CAP/IConsumerHandler.Default.cs index cf2936a..6eb85ea 100644 --- a/src/DotNetCore.CAP/IConsumerHandler.Default.cs +++ b/src/DotNetCore.CAP/IConsumerHandler.Default.cs @@ -114,7 +114,7 @@ namespace DotNetCore.CAP private CapReceivedMessage StoreMessage(IServiceScope serviceScope, MessageContext messageContext) { var provider = serviceScope.ServiceProvider; - var messageStore = provider.GetRequiredService(); + var messageStore = provider.GetRequiredService(); var receivedMessage = new CapReceivedMessage(messageContext) { StatusName = StatusName.Enqueued, @@ -126,13 +126,17 @@ namespace DotNetCore.CAP private void ProcessMessage(IServiceScope serviceScope, CapReceivedMessage receivedMessage) { var provider = serviceScope.ServiceProvider; - var messageStore = provider.GetRequiredService(); + var messageStore = provider.GetRequiredService(); try { var executeDescriptorGroup = _selector.GetTopicExector(receivedMessage.KeyName); if (executeDescriptorGroup.ContainsKey(receivedMessage.Group)) { + messageStore.FetchNextReceivedMessageAsync + + + messageStore.ChangeReceivedMessageStateAsync(receivedMessage, StatusName.Processing).Wait(); // If there are multiple consumers in the same group, we will take the first diff --git a/src/DotNetCore.CAP/IStorageConnection.cs b/src/DotNetCore.CAP/IStorageConnection.cs index da81af6..99a48ff 100644 --- a/src/DotNetCore.CAP/IStorageConnection.cs +++ b/src/DotNetCore.CAP/IStorageConnection.cs @@ -10,13 +10,7 @@ namespace DotNetCore.CAP public interface IStorageConnection : IDisposable { - //Sent messages - - /// - /// Stores the message. - /// - /// The message to store. - Task StoreSentMessageAsync(CapSentMessage message); + //Sent messages /// /// Returns the message with the given id. @@ -56,7 +50,7 @@ namespace DotNetCore.CAP /// /// Returns the next message to be enqueued. /// - Task GetNextReceviedMessageToBeEnqueuedAsync(); + Task GetNextReceviedMessageToBeEnqueuedAsync(); //----------------------------------------- diff --git a/src/DotNetCore.CAP/Job/IJobProcessor.JobQueuer.cs b/src/DotNetCore.CAP/Job/IJobProcessor.JobQueuer.cs new file mode 100644 index 0000000..d297d31 --- /dev/null +++ b/src/DotNetCore.CAP/Job/IJobProcessor.JobQueuer.cs @@ -0,0 +1,65 @@ +using System; +using System.Threading; +using System.Threading.Tasks; +using DotNetCore.CAP.Job.States; +using DotNetCore.CAP.Models; +using Microsoft.Extensions.DependencyInjection; +using Microsoft.Extensions.Logging; + +namespace DotNetCore.CAP.Job +{ + public class JobQueuer : IJobProcessor + { + private ILogger _logger; + private JobsOptions _options; + private IStateChanger _stateChanger; + private IServiceProvider _provider; + + internal static readonly AutoResetEvent PulseEvent = new AutoResetEvent(true); + private TimeSpan _pollingDelay; + + public JobQueuer( + ILogger logger, + JobsOptions options, + IStateChanger stateChanger, + IServiceProvider provider) + { + _logger = logger; + _options = options; + _stateChanger = stateChanger; + _provider = provider; + + _pollingDelay = TimeSpan.FromSeconds(_options.PollingDelay); + } + + public async Task ProcessAsync(ProcessingContext context) + { + using (var scope = _provider.CreateScope()) + { + CapSentMessage sentMessage; + CapReceivedMessage receivedMessage; + var provider = scope.ServiceProvider; + var connection = provider.GetRequiredService(); + + while ( + !context.IsStopping && + (sentMessage = await connection.GetNextSentMessageToBeEnqueuedAsync()) != null) + + { + var state = new EnqueuedState(); + + using (var transaction = connection.CreateTransaction()) + { + _stateChanger.ChangeState(sentMessage, state, transaction); + await transaction.CommitAsync(); + } + } + } + + context.ThrowIfStopping(); + + DelayedJobProcessor.PulseEvent.Set(); + await WaitHandleEx.WaitAnyAsync(PulseEvent, context.CancellationToken.WaitHandle, _pollingDelay); + } + } +} diff --git a/src/DotNetCore.CAP/Job/States/IState.Enqueued.cs b/src/DotNetCore.CAP/Job/States/IState.Enqueued.cs new file mode 100644 index 0000000..6588177 --- /dev/null +++ b/src/DotNetCore.CAP/Job/States/IState.Enqueued.cs @@ -0,0 +1,24 @@ +using System; +using DotNetCore.CAP.Models; + +namespace DotNetCore.CAP.Job.States +{ + public class EnqueuedState : IState + { + public const string StateName = "Enqueued"; + + public TimeSpan? ExpiresAfter => null; + + public string Name => StateName; + + public void Apply(CapSentMessage message, IStorageTransaction transaction) + { + transaction.EnqueueMessage(message); + } + + public void Apply(CapReceivedMessage message, IStorageTransaction transaction) + { + transaction.EnqueueMessage(message); + } + } +} \ No newline at end of file diff --git a/src/DotNetCore.CAP/Job/States/IState.Failed.cs b/src/DotNetCore.CAP/Job/States/IState.Failed.cs new file mode 100644 index 0000000..c779856 --- /dev/null +++ b/src/DotNetCore.CAP/Job/States/IState.Failed.cs @@ -0,0 +1,22 @@ +using System; +using DotNetCore.CAP.Models; + +namespace DotNetCore.CAP.Job.States +{ + public class FailedState : IState + { + public const string StateName = "Failed"; + + public TimeSpan? ExpiresAfter => TimeSpan.FromDays(15); + + public string Name => StateName; + + public void Apply(CapSentMessage message, IStorageTransaction transaction) + { + } + + public void Apply(CapReceivedMessage message, IStorageTransaction transaction) + { + } + } +} \ No newline at end of file diff --git a/src/DotNetCore.CAP/Job/States/IState.Processing.cs b/src/DotNetCore.CAP/Job/States/IState.Processing.cs new file mode 100644 index 0000000..a5564a8 --- /dev/null +++ b/src/DotNetCore.CAP/Job/States/IState.Processing.cs @@ -0,0 +1,22 @@ +using System; +using DotNetCore.CAP.Models; + +namespace DotNetCore.CAP.Job.States +{ + public class ProcessingState : IState + { + public const string StateName = "Processing"; + + public TimeSpan? ExpiresAfter => null; + + public string Name => StateName; + + public void Apply(CapSentMessage message, IStorageTransaction transaction) + { + } + + public void Apply(CapReceivedMessage message, IStorageTransaction transaction) + { + } + } +} \ No newline at end of file diff --git a/src/DotNetCore.CAP/Job/States/IState.Scheduled.cs b/src/DotNetCore.CAP/Job/States/IState.Scheduled.cs new file mode 100644 index 0000000..6a38697 --- /dev/null +++ b/src/DotNetCore.CAP/Job/States/IState.Scheduled.cs @@ -0,0 +1,22 @@ +using System; +using DotNetCore.CAP.Models; + +namespace DotNetCore.CAP.Job.States +{ + public class ScheduledState : IState + { + public const string StateName = "Scheduled"; + + public TimeSpan? ExpiresAfter => null; + + public string Name => StateName; + + public void Apply(CapSentMessage message, IStorageTransaction transaction) + { + } + + public void Apply(CapReceivedMessage message, IStorageTransaction transaction) + { + } + } +} \ No newline at end of file diff --git a/src/DotNetCore.CAP/Job/States/IState.Succeeded.cs b/src/DotNetCore.CAP/Job/States/IState.Succeeded.cs new file mode 100644 index 0000000..384de56 --- /dev/null +++ b/src/DotNetCore.CAP/Job/States/IState.Succeeded.cs @@ -0,0 +1,22 @@ +using System; +using DotNetCore.CAP.Models; + +namespace DotNetCore.CAP.Job.States +{ + public class SucceededState : IState + { + public const string StateName = "Succeeded"; + + public TimeSpan? ExpiresAfter => TimeSpan.FromHours(1); + + public string Name => StateName; + + public void Apply(CapSentMessage message, IStorageTransaction transaction) + { + } + + public void Apply(CapReceivedMessage message, IStorageTransaction transaction) + { + } + } +} \ No newline at end of file diff --git a/src/DotNetCore.CAP/Job/States/IState.cs b/src/DotNetCore.CAP/Job/States/IState.cs new file mode 100644 index 0000000..2219dcb --- /dev/null +++ b/src/DotNetCore.CAP/Job/States/IState.cs @@ -0,0 +1,16 @@ +using System; +using DotNetCore.CAP.Models; + +namespace DotNetCore.CAP.Job.States +{ + public interface IState + { + TimeSpan? ExpiresAfter { get; } + + string Name { get; } + + void Apply(CapSentMessage message, IStorageTransaction transaction); + + void Apply(CapReceivedMessage message, IStorageTransaction transaction); + } +} \ No newline at end of file diff --git a/src/DotNetCore.CAP/Job/States/IStateChanger.Default.cs b/src/DotNetCore.CAP/Job/States/IStateChanger.Default.cs new file mode 100644 index 0000000..b3f2d2a --- /dev/null +++ b/src/DotNetCore.CAP/Job/States/IStateChanger.Default.cs @@ -0,0 +1,41 @@ +using DotNetCore.CAP.Models; + +namespace DotNetCore.CAP.Job.States +{ + public class StateChanger : IStateChanger + { + public void ChangeState(CapSentMessage message, IState state, IStorageTransaction transaction) + { + //var now = DateTime.UtcNow; + //if (state.ExpiresAfter != null) + //{ + // message.ExpiresAt = now.Add(state.ExpiresAfter.Value); + //} + //else + //{ + // message.ExpiresAt = null; + //} + + message.StatusName = state.Name; + state.Apply(message, transaction); + transaction.UpdateMessage(message); + } + + public void ChangeState(CapReceivedMessage message, IState state, IStorageTransaction transaction) + { + //var now = DateTime.UtcNow; + //if (state.ExpiresAfter != null) + //{ + // job.ExpiresAt = now.Add(state.ExpiresAfter.Value); + //} + //else + //{ + // job.ExpiresAt = null; + //} + + message.StatusName = state.Name; + state.Apply(message, transaction); + transaction.UpdateMessage(message); + } + } +} \ No newline at end of file diff --git a/src/DotNetCore.CAP/Job/States/IStateChanger.Extensions.cs b/src/DotNetCore.CAP/Job/States/IStateChanger.Extensions.cs new file mode 100644 index 0000000..27ec4e9 --- /dev/null +++ b/src/DotNetCore.CAP/Job/States/IStateChanger.Extensions.cs @@ -0,0 +1,28 @@ +using System.Threading.Tasks; +using DotNetCore.CAP.Models; + +namespace DotNetCore.CAP.Job.States +{ + public static class StateChangerExtensions + { + public static async Task ChangeStateAsync( + this IStateChanger @this, CapSentMessage message, IState state, IStorageConnection connection) + { + using (var transaction = connection.CreateTransaction()) + { + @this.ChangeState(message, state, transaction); + await transaction.CommitAsync(); + } + } + + public static async Task ChangeStateAsync( + this IStateChanger @this, CapReceivedMessage message, IState state, IStorageConnection connection) + { + using (var transaction = connection.CreateTransaction()) + { + @this.ChangeState(message, state, transaction); + await transaction.CommitAsync(); + } + } + } +} \ No newline at end of file diff --git a/src/DotNetCore.CAP/Job/States/IStateChanger.cs b/src/DotNetCore.CAP/Job/States/IStateChanger.cs new file mode 100644 index 0000000..662e4e1 --- /dev/null +++ b/src/DotNetCore.CAP/Job/States/IStateChanger.cs @@ -0,0 +1,11 @@ +using DotNetCore.CAP.Models; + +namespace DotNetCore.CAP.Job.States +{ + public interface IStateChanger + { + void ChangeState(CapSentMessage message, IState state, IStorageTransaction transaction); + + void ChangeState(CapReceivedMessage message, IState state, IStorageTransaction transaction); + } +} \ No newline at end of file diff --git a/src/DotNetCore.CAP/OperateResult.cs b/src/DotNetCore.CAP/OperateResult.cs index c52929e..41fcc33 100644 --- a/src/DotNetCore.CAP/OperateResult.cs +++ b/src/DotNetCore.CAP/OperateResult.cs @@ -1,4 +1,5 @@ -using System.Collections.Generic; +using System; +using System.Collections.Generic; using System.Linq; namespace DotNetCore.CAP @@ -18,6 +19,8 @@ namespace DotNetCore.CAP /// public bool Succeeded { get; set; } + public Exception Exception { get; set; } + /// /// An of s containing an errors /// that occurred during the operation. @@ -46,6 +49,17 @@ namespace DotNetCore.CAP return result; } + public static OperateResult Failed(Exception ex, params OperateError[] errors) + { + var result = new OperateResult { Succeeded = false }; + result.Exception = ex; + if (errors != null) + { + result._errors.AddRange(errors); + } + return result; + } + /// /// Converts the value of the current object to its equivalent string representation. /// From 9cbd1dc0ee5a5ac81defecf4dfd9cc07ee7ea744 Mon Sep 17 00:00:00 2001 From: Savorboard Date: Wed, 12 Jul 2017 01:03:54 +0800 Subject: [PATCH 04/68] Refactor storage --- samples/Sample.Kafka/Startup.cs | 7 +- .../CAP.EFOptions.cs | 6 + .../CapDbContext.cs | 9 +- .../CapPublisherExtensions.cs | 51 +++++ .../DotNetCore.CAP.EntityFrameworkCore.csproj | 1 + .../EFStorageConnection.cs | 4 +- .../HelperExtensions.cs | 30 --- .../20170711154104_InitializeDB.Designer.cs | 90 ++++++++ .../Migrations/20170711154104_InitializeDB.cs | 95 +++++++++ .../Migrations/CapDbContextModelSnapshot.cs | 89 ++++++++ .../IProcessor.KafkaJobProcessor.cs | 55 ++--- .../IProcessor.RabbitJobProcessor.cs | 5 +- .../IConsumerHandler.Default.cs | 48 ++--- src/DotNetCore.CAP/IProcessingServer.cs | 2 + .../Infrastructure/WaitHandleEx.cs | 3 + src/DotNetCore.CAP/Job/ComputedCronJob.cs | 57 ----- src/DotNetCore.CAP/Job/Cron.cs | 198 ------------------ src/DotNetCore.CAP/Job/CronJob.cs | 37 ---- .../Job/CronJobRegistry.Default.cs | 15 -- src/DotNetCore.CAP/Job/CronJobRegistry.cs | 68 ------ src/DotNetCore.CAP/Job/IJob.CapJob.cs | 48 ++--- .../Job/IJobProcessor.CronJob.cs | 170 --------------- .../Job/IJobProcessor.JobQueuer.cs | 19 +- .../Job/IMessageJobProcessor.cs | 11 + .../Job/IProcessingServer.Job.cs | 35 +++- src/DotNetCore.CAP/Job/ProcessingContext.cs | 5 - test/DotNetCore.CAP.Test/NoopMessageStore.cs | 37 ---- test/Shared/MessageManagerTestBase.cs | 48 ++--- 28 files changed, 501 insertions(+), 742 deletions(-) create mode 100644 src/DotNetCore.CAP.EntityFrameworkCore/CapPublisherExtensions.cs delete mode 100644 src/DotNetCore.CAP.EntityFrameworkCore/HelperExtensions.cs create mode 100644 src/DotNetCore.CAP.EntityFrameworkCore/Migrations/20170711154104_InitializeDB.Designer.cs create mode 100644 src/DotNetCore.CAP.EntityFrameworkCore/Migrations/20170711154104_InitializeDB.cs create mode 100644 src/DotNetCore.CAP.EntityFrameworkCore/Migrations/CapDbContextModelSnapshot.cs delete mode 100644 src/DotNetCore.CAP/Job/ComputedCronJob.cs delete mode 100644 src/DotNetCore.CAP/Job/Cron.cs delete mode 100644 src/DotNetCore.CAP/Job/CronJob.cs delete mode 100644 src/DotNetCore.CAP/Job/CronJobRegistry.Default.cs delete mode 100644 src/DotNetCore.CAP/Job/CronJobRegistry.cs delete mode 100644 src/DotNetCore.CAP/Job/IJobProcessor.CronJob.cs create mode 100644 src/DotNetCore.CAP/Job/IMessageJobProcessor.cs diff --git a/samples/Sample.Kafka/Startup.cs b/samples/Sample.Kafka/Startup.cs index 1858212..aa2ff25 100644 --- a/samples/Sample.Kafka/Startup.cs +++ b/samples/Sample.Kafka/Startup.cs @@ -1,4 +1,5 @@ -using Microsoft.AspNetCore.Builder; +using DotNetCore.CAP.EntityFrameworkCore; +using Microsoft.AspNetCore.Builder; using Microsoft.AspNetCore.Hosting; using Microsoft.Extensions.Configuration; using Microsoft.Extensions.DependencyInjection; @@ -23,10 +24,10 @@ namespace Sample.Kafka // This method gets called by the runtime. Use this method to add services to the container. public void ConfigureServices(IServiceCollection services) { - services.AddDbContext(); + services.AddDbContext(); services.AddCap() - .AddEntityFrameworkStores() + .AddEntityFrameworkStores() .AddRabbitMQ(x => { x.HostName = "localhost"; diff --git a/src/DotNetCore.CAP.EntityFrameworkCore/CAP.EFOptions.cs b/src/DotNetCore.CAP.EntityFrameworkCore/CAP.EFOptions.cs index b019803..6e2b118 100644 --- a/src/DotNetCore.CAP.EntityFrameworkCore/CAP.EFOptions.cs +++ b/src/DotNetCore.CAP.EntityFrameworkCore/CAP.EFOptions.cs @@ -9,6 +9,12 @@ namespace DotNetCore.CAP.EntityFrameworkCore public const string DefaultSchema = "cap"; public const string DefaultMigrationsHistoryTableName = "__EFMigrationsHistory"; + + public EFOptions() + { + ConnectionString = "Server=DESKTOP-M9R8T31;Initial Catalog=WebApp1;User Id=sa;Password=P@ssw0rd;MultipleActiveResultSets=True"; + } + /// /// Gets or sets the database's connection string that will be used to store database entities. /// diff --git a/src/DotNetCore.CAP.EntityFrameworkCore/CapDbContext.cs b/src/DotNetCore.CAP.EntityFrameworkCore/CapDbContext.cs index b255f1d..85f0d2e 100644 --- a/src/DotNetCore.CAP.EntityFrameworkCore/CapDbContext.cs +++ b/src/DotNetCore.CAP.EntityFrameworkCore/CapDbContext.cs @@ -15,7 +15,9 @@ namespace DotNetCore.CAP.EntityFrameworkCore /// /// Initializes a new instance of the . /// - public CapDbContext() { } + public CapDbContext() { + _efOptions = new EFOptions(); + } /// /// Initializes a new instance of the . @@ -65,5 +67,10 @@ namespace DotNetCore.CAP.EntityFrameworkCore b.Property(p => p.StatusName).IsRequired().HasMaxLength(50); }); } + + //protected override void OnConfiguring(DbContextOptionsBuilder optionsBuilder) + //{ + // optionsBuilder.UseSqlServer("Server=DESKTOP-M9R8T31;Initial Catalog=WebApp1;User Id=sa;Password=P@ssw0rd;MultipleActiveResultSets=True"); + //} } } \ No newline at end of file diff --git a/src/DotNetCore.CAP.EntityFrameworkCore/CapPublisherExtensions.cs b/src/DotNetCore.CAP.EntityFrameworkCore/CapPublisherExtensions.cs new file mode 100644 index 0000000..ede5cab --- /dev/null +++ b/src/DotNetCore.CAP.EntityFrameworkCore/CapPublisherExtensions.cs @@ -0,0 +1,51 @@ +using System; +using System.Collections.Generic; +using System.Data; +using System.Threading.Tasks; +using DotNetCore.CAP.Models; +using Dapper; +using Microsoft.EntityFrameworkCore; +using Microsoft.EntityFrameworkCore.Infrastructure; +using DotNetCore.CAP.Infrastructure; + +namespace DotNetCore.CAP +{ + static class CapPublisherExtensions + { + public static async Task Publish(this ICapPublisher publisher, string topic, string content, DatabaseFacade database) + { + var connection = database.GetDbConnection(); + var transaction = database.CurrentTransaction; + transaction = transaction ?? await database.BeginTransactionAsync(IsolationLevel.ReadCommitted); + + var message = new CapSentMessage + { + KeyName = topic, + Content = content, + StatusName = StatusName.Enqueued + }; + + var sql = "INSERT INTO [cap].[CapSentMessages] ([Id],[Added],[Content],[KeyName],[LastRun],[Retries],[StatusName])VALUES(@Id,@Added,@Content,@KeyName,@LastRun,@Retries,@StatusName)"; + await connection.ExecuteAsync(sql, transaction); + + JobQueuer.PulseEvent.Set(); + + } + + public static async Task Publish(this ICapPublisher publisher, string topic, string content, IDbConnection connection,IDbTransaction transaction) + { + var message = new CapSentMessage + { + KeyName = topic, + Content = content, + StatusName = StatusName.Enqueued + }; + + var sql = "INSERT INTO [cap].[CapSentMessages] ([Id],[Added],[Content],[KeyName],[LastRun],[Retries],[StatusName])VALUES(@Id,@Added,@Content,@KeyName,@LastRun,@Retries,@StatusName)"; + return await connection.ExecuteAsync(sql, transaction); + + JobQueuer.PulseEvent.Set(); + } + + } +} \ No newline at end of file diff --git a/src/DotNetCore.CAP.EntityFrameworkCore/DotNetCore.CAP.EntityFrameworkCore.csproj b/src/DotNetCore.CAP.EntityFrameworkCore/DotNetCore.CAP.EntityFrameworkCore.csproj index 6a6422c..d532199 100644 --- a/src/DotNetCore.CAP.EntityFrameworkCore/DotNetCore.CAP.EntityFrameworkCore.csproj +++ b/src/DotNetCore.CAP.EntityFrameworkCore/DotNetCore.CAP.EntityFrameworkCore.csproj @@ -14,6 +14,7 @@ + diff --git a/src/DotNetCore.CAP.EntityFrameworkCore/EFStorageConnection.cs b/src/DotNetCore.CAP.EntityFrameworkCore/EFStorageConnection.cs index d0ed080..cc302f7 100644 --- a/src/DotNetCore.CAP.EntityFrameworkCore/EFStorageConnection.cs +++ b/src/DotNetCore.CAP.EntityFrameworkCore/EFStorageConnection.cs @@ -96,7 +96,7 @@ namespace DotNetCore.CAP.EntityFrameworkCore throw new NotImplementedException(); } - public Task GetNextReceviedMessageToBeEnqueuedAsync() + public Task GetNextReceviedMessageToBeEnqueuedAsync() { throw new NotImplementedException(); } @@ -113,6 +113,6 @@ namespace DotNetCore.CAP.EntityFrameworkCore public void Dispose() { - } + } } } diff --git a/src/DotNetCore.CAP.EntityFrameworkCore/HelperExtensions.cs b/src/DotNetCore.CAP.EntityFrameworkCore/HelperExtensions.cs deleted file mode 100644 index 02342d6..0000000 --- a/src/DotNetCore.CAP.EntityFrameworkCore/HelperExtensions.cs +++ /dev/null @@ -1,30 +0,0 @@ -using System; -using System.Collections.Generic; -using System.Data; - -namespace DotNetCore.CAP.EntityFrameworkCore -{ - static class HelperExtensions - { - public static void Execute(this IDbConnection connection, string sql, IDbTransaction transcation = null) - { - try - { - connection.Open(); - using (var command = connection.CreateCommand()) - { - command.CommandText = "SELELCT 1"; - if (transcation != null) - command.Transaction = transcation; - command.ExecuteNonQuery(); - } - } - finally - { - connection.Close(); - } - } - - - } -} \ No newline at end of file diff --git a/src/DotNetCore.CAP.EntityFrameworkCore/Migrations/20170711154104_InitializeDB.Designer.cs b/src/DotNetCore.CAP.EntityFrameworkCore/Migrations/20170711154104_InitializeDB.Designer.cs new file mode 100644 index 0000000..0f9da26 --- /dev/null +++ b/src/DotNetCore.CAP.EntityFrameworkCore/Migrations/20170711154104_InitializeDB.Designer.cs @@ -0,0 +1,90 @@ +using System; +using Microsoft.EntityFrameworkCore; +using Microsoft.EntityFrameworkCore.Infrastructure; +using Microsoft.EntityFrameworkCore.Metadata; +using Microsoft.EntityFrameworkCore.Migrations; +using DotNetCore.CAP.EntityFrameworkCore; + +namespace DotNetCore.CAP.EntityFrameworkCore.Migrations +{ + [DbContext(typeof(CapDbContext))] + [Migration("20170711154104_InitializeDB")] + partial class InitializeDB + { + protected override void BuildTargetModel(ModelBuilder modelBuilder) + { + modelBuilder + .HasDefaultSchema("cap") + .HasAnnotation("ProductVersion", "1.1.2") + .HasAnnotation("SqlServer:ValueGenerationStrategy", SqlServerValueGenerationStrategy.IdentityColumn); + + modelBuilder.Entity("DotNetCore.CAP.Models.CapQueue", b => + { + b.Property("Id") + .ValueGeneratedOnAdd(); + + b.Property("MessageId"); + + b.Property("Type"); + + b.HasKey("Id"); + + b.ToTable("CapQueue"); + }); + + modelBuilder.Entity("DotNetCore.CAP.Models.CapReceivedMessage", b => + { + b.Property("Id") + .ValueGeneratedOnAdd(); + + b.Property("Added"); + + b.Property("Content"); + + b.Property("Group"); + + b.Property("KeyName"); + + b.Property("LastRun"); + + b.Property("Retries"); + + b.Property("StatusName") + .IsRequired() + .HasMaxLength(50); + + b.HasKey("Id"); + + b.HasIndex("StatusName"); + + b.ToTable("CapReceivedMessages"); + }); + + modelBuilder.Entity("DotNetCore.CAP.Models.CapSentMessage", b => + { + b.Property("Id") + .ValueGeneratedOnAdd(); + + b.Property("Added"); + + b.Property("Content"); + + b.Property("KeyName"); + + b.Property("LastRun"); + + b.Property("Retries"); + + b.Property("StatusName") + .IsRequired() + .HasMaxLength(50); + + b.HasKey("Id"); + + b.HasIndex("StatusName"); + + b.ToTable("CapSentMessages"); + }); + } + } +} diff --git a/src/DotNetCore.CAP.EntityFrameworkCore/Migrations/20170711154104_InitializeDB.cs b/src/DotNetCore.CAP.EntityFrameworkCore/Migrations/20170711154104_InitializeDB.cs new file mode 100644 index 0000000..dd96f24 --- /dev/null +++ b/src/DotNetCore.CAP.EntityFrameworkCore/Migrations/20170711154104_InitializeDB.cs @@ -0,0 +1,95 @@ +using System; +using System.Collections.Generic; +using Microsoft.EntityFrameworkCore.Migrations; +using Microsoft.EntityFrameworkCore.Metadata; + +namespace DotNetCore.CAP.EntityFrameworkCore.Migrations +{ + public partial class InitializeDB : Migration + { + protected override void Up(MigrationBuilder migrationBuilder) + { + migrationBuilder.EnsureSchema( + name: "cap"); + + migrationBuilder.CreateTable( + name: "CapQueue", + schema: "cap", + columns: table => new + { + Id = table.Column(nullable: false) + .Annotation("SqlServer:ValueGenerationStrategy", SqlServerValueGenerationStrategy.IdentityColumn), + MessageId = table.Column(nullable: true), + Type = table.Column(nullable: false) + }, + constraints: table => + { + table.PrimaryKey("PK_CapQueue", x => x.Id); + }); + + migrationBuilder.CreateTable( + name: "CapReceivedMessages", + schema: "cap", + columns: table => new + { + Id = table.Column(nullable: false), + Added = table.Column(nullable: false), + Content = table.Column(nullable: true), + Group = table.Column(nullable: true), + KeyName = table.Column(nullable: true), + LastRun = table.Column(nullable: true), + Retries = table.Column(nullable: false), + StatusName = table.Column(maxLength: 50, nullable: false) + }, + constraints: table => + { + table.PrimaryKey("PK_CapReceivedMessages", x => x.Id); + }); + + migrationBuilder.CreateTable( + name: "CapSentMessages", + schema: "cap", + columns: table => new + { + Id = table.Column(nullable: false), + Added = table.Column(nullable: false), + Content = table.Column(nullable: true), + KeyName = table.Column(nullable: true), + LastRun = table.Column(nullable: true), + Retries = table.Column(nullable: false), + StatusName = table.Column(maxLength: 50, nullable: false) + }, + constraints: table => + { + table.PrimaryKey("PK_CapSentMessages", x => x.Id); + }); + + migrationBuilder.CreateIndex( + name: "IX_CapReceivedMessages_StatusName", + schema: "cap", + table: "CapReceivedMessages", + column: "StatusName"); + + migrationBuilder.CreateIndex( + name: "IX_CapSentMessages_StatusName", + schema: "cap", + table: "CapSentMessages", + column: "StatusName"); + } + + protected override void Down(MigrationBuilder migrationBuilder) + { + migrationBuilder.DropTable( + name: "CapQueue", + schema: "cap"); + + migrationBuilder.DropTable( + name: "CapReceivedMessages", + schema: "cap"); + + migrationBuilder.DropTable( + name: "CapSentMessages", + schema: "cap"); + } + } +} diff --git a/src/DotNetCore.CAP.EntityFrameworkCore/Migrations/CapDbContextModelSnapshot.cs b/src/DotNetCore.CAP.EntityFrameworkCore/Migrations/CapDbContextModelSnapshot.cs new file mode 100644 index 0000000..765fa0f --- /dev/null +++ b/src/DotNetCore.CAP.EntityFrameworkCore/Migrations/CapDbContextModelSnapshot.cs @@ -0,0 +1,89 @@ +using System; +using Microsoft.EntityFrameworkCore; +using Microsoft.EntityFrameworkCore.Infrastructure; +using Microsoft.EntityFrameworkCore.Metadata; +using Microsoft.EntityFrameworkCore.Migrations; +using DotNetCore.CAP.EntityFrameworkCore; + +namespace DotNetCore.CAP.EntityFrameworkCore.Migrations +{ + [DbContext(typeof(CapDbContext))] + partial class CapDbContextModelSnapshot : ModelSnapshot + { + protected override void BuildModel(ModelBuilder modelBuilder) + { + modelBuilder + .HasDefaultSchema("cap") + .HasAnnotation("ProductVersion", "1.1.2") + .HasAnnotation("SqlServer:ValueGenerationStrategy", SqlServerValueGenerationStrategy.IdentityColumn); + + modelBuilder.Entity("DotNetCore.CAP.Models.CapQueue", b => + { + b.Property("Id") + .ValueGeneratedOnAdd(); + + b.Property("MessageId"); + + b.Property("Type"); + + b.HasKey("Id"); + + b.ToTable("CapQueue"); + }); + + modelBuilder.Entity("DotNetCore.CAP.Models.CapReceivedMessage", b => + { + b.Property("Id") + .ValueGeneratedOnAdd(); + + b.Property("Added"); + + b.Property("Content"); + + b.Property("Group"); + + b.Property("KeyName"); + + b.Property("LastRun"); + + b.Property("Retries"); + + b.Property("StatusName") + .IsRequired() + .HasMaxLength(50); + + b.HasKey("Id"); + + b.HasIndex("StatusName"); + + b.ToTable("CapReceivedMessages"); + }); + + modelBuilder.Entity("DotNetCore.CAP.Models.CapSentMessage", b => + { + b.Property("Id") + .ValueGeneratedOnAdd(); + + b.Property("Added"); + + b.Property("Content"); + + b.Property("KeyName"); + + b.Property("LastRun"); + + b.Property("Retries"); + + b.Property("StatusName") + .IsRequired() + .HasMaxLength(50); + + b.HasKey("Id"); + + b.HasIndex("StatusName"); + + b.ToTable("CapSentMessages"); + }); + } + } +} diff --git a/src/DotNetCore.CAP.Kafka/IProcessor.KafkaJobProcessor.cs b/src/DotNetCore.CAP.Kafka/IProcessor.KafkaJobProcessor.cs index 3edda96..678feda 100644 --- a/src/DotNetCore.CAP.Kafka/IProcessor.KafkaJobProcessor.cs +++ b/src/DotNetCore.CAP.Kafka/IProcessor.KafkaJobProcessor.cs @@ -78,33 +78,34 @@ namespace DotNetCore.CAP.Kafka private async Task Step(ProcessingContext context) { - using (var scopedContext = context.CreateScope()) - { - var provider = scopedContext.Provider; - var messageStore = provider.GetRequiredService(); - var message = await messageStore.GetNextSentMessageToBeEnqueuedAsync(); - if (message == null) return true; - try - { - var sp = Stopwatch.StartNew(); - message.StatusName = StatusName.Processing; - await messageStore.UpdateSentMessageAsync(message); - - await ExecuteJobAsync(message.KeyName, message.Content); - - sp.Stop(); - - message.StatusName = StatusName.Succeeded; - await messageStore.UpdateSentMessageAsync(message); - _logger.JobExecuted(sp.Elapsed.TotalSeconds); - } - catch (Exception ex) - { - _logger.ExceptionOccuredWhileExecutingJob(message.KeyName, ex); - return false; - } - } - return true; + throw new NotImplementedException(); + // using (var scopedContext = context.CreateScope()) + // { + // var provider = scopedContext.Provider; + // var messageStore = provider.GetRequiredService(); + // var message = await messageStore.GetNextSentMessageToBeEnqueuedAsync(); + // if (message == null) return true; + // try + // { + // var sp = Stopwatch.StartNew(); + // message.StatusName = StatusName.Processing; + // await messageStore.UpdateSentMessageAsync(message); + + // await ExecuteJobAsync(message.KeyName, message.Content); + + // sp.Stop(); + + // message.StatusName = StatusName.Succeeded; + // await messageStore.UpdateSentMessageAsync(message); + // _logger.JobExecuted(sp.Elapsed.TotalSeconds); + // } + // catch (Exception ex) + // { + // _logger.ExceptionOccuredWhileExecutingJob(message.KeyName, ex); + // return false; + // } + // } + // return true; } private Task ExecuteJobAsync(string topic, string content) diff --git a/src/DotNetCore.CAP.RabbitMQ/IProcessor.RabbitJobProcessor.cs b/src/DotNetCore.CAP.RabbitMQ/IProcessor.RabbitJobProcessor.cs index f50a0a5..dd884fd 100644 --- a/src/DotNetCore.CAP.RabbitMQ/IProcessor.RabbitJobProcessor.cs +++ b/src/DotNetCore.CAP.RabbitMQ/IProcessor.RabbitJobProcessor.cs @@ -23,7 +23,6 @@ namespace DotNetCore.CAP.RabbitMQ private readonly ILogger _logger; private readonly TimeSpan _pollingDelay; - internal static readonly AutoResetEvent PulseEvent = new AutoResetEvent(true); public RabbitJobProcessor( IOptions capOptions, @@ -67,7 +66,7 @@ namespace DotNetCore.CAP.RabbitMQ var token = GetTokenToWaitOn(context); } - await WaitHandleEx.WaitAnyAsync(PulseEvent, + await WaitHandleEx.WaitAnyAsync(WaitHandleEx.SentPulseEvent, context.CancellationToken.WaitHandle, _pollingDelay); } finally @@ -87,7 +86,7 @@ namespace DotNetCore.CAP.RabbitMQ using (var scopedContext = context.CreateScope()) { var provider = scopedContext.Provider; - var messageStore = provider.GetRequiredService(); + //var messageStore = provider.GetRequiredService(); var connection = provider.GetRequiredService(); if ((fetched = await connection.FetchNextSentMessageAsync()) != null) diff --git a/src/DotNetCore.CAP/IConsumerHandler.Default.cs b/src/DotNetCore.CAP/IConsumerHandler.Default.cs index 6eb85ea..ff11500 100644 --- a/src/DotNetCore.CAP/IConsumerHandler.Default.cs +++ b/src/DotNetCore.CAP/IConsumerHandler.Default.cs @@ -106,7 +106,7 @@ namespace DotNetCore.CAP { var receviedMessage = StoreMessage(scope, message); client.Commit(); - ProcessMessage(scope, receviedMessage); + // ProcessMessage(scope, receviedMessage); } }; } @@ -123,36 +123,36 @@ namespace DotNetCore.CAP return receivedMessage; } - private void ProcessMessage(IServiceScope serviceScope, CapReceivedMessage receivedMessage) - { - var provider = serviceScope.ServiceProvider; - var messageStore = provider.GetRequiredService(); - try - { - var executeDescriptorGroup = _selector.GetTopicExector(receivedMessage.KeyName); + //private void ProcessMessage(IServiceScope serviceScope, CapReceivedMessage receivedMessage) + //{ + // var provider = serviceScope.ServiceProvider; + // var messageStore = provider.GetRequiredService(); + // try + // { + // var executeDescriptorGroup = _selector.GetTopicExector(receivedMessage.KeyName); - if (executeDescriptorGroup.ContainsKey(receivedMessage.Group)) - { - messageStore.FetchNextReceivedMessageAsync + // if (executeDescriptorGroup.ContainsKey(receivedMessage.Group)) + // { + // messageStore.FetchNextReceivedMessageAsync - messageStore.ChangeReceivedMessageStateAsync(receivedMessage, StatusName.Processing).Wait(); + // messageStore.ChangeReceivedMessageStateAsync(receivedMessage, StatusName.Processing).Wait(); - // If there are multiple consumers in the same group, we will take the first - var executeDescriptor = executeDescriptorGroup[receivedMessage.Group][0]; - var consumerContext = new ConsumerContext(executeDescriptor, receivedMessage.ToMessageContext()); + // // If there are multiple consumers in the same group, we will take the first + // var executeDescriptor = executeDescriptorGroup[receivedMessage.Group][0]; + // var consumerContext = new ConsumerContext(executeDescriptor, receivedMessage.ToMessageContext()); - _consumerInvokerFactory.CreateInvoker(consumerContext).InvokeAsync(); + // _consumerInvokerFactory.CreateInvoker(consumerContext).InvokeAsync(); - messageStore.ChangeReceivedMessageStateAsync(receivedMessage, StatusName.Succeeded).Wait(); - } - } - catch (Exception ex) - { - _logger.ConsumerMethodExecutingFailed($"Group:{receivedMessage.Group}, Topic:{receivedMessage.KeyName}", ex); - } - } + // messageStore.ChangeReceivedMessageStateAsync(receivedMessage, StatusName.Succeeded).Wait(); + // } + // } + // catch (Exception ex) + // { + // _logger.ConsumerMethodExecutingFailed($"Group:{receivedMessage.Group}, Topic:{receivedMessage.KeyName}", ex); + // } + //} } diff --git a/src/DotNetCore.CAP/IProcessingServer.cs b/src/DotNetCore.CAP/IProcessingServer.cs index ccb01f3..f5f3533 100644 --- a/src/DotNetCore.CAP/IProcessingServer.cs +++ b/src/DotNetCore.CAP/IProcessingServer.cs @@ -7,6 +7,8 @@ namespace DotNetCore.CAP /// public interface IProcessingServer : IDisposable { + void Pulse(); + void Start(); } } \ No newline at end of file diff --git a/src/DotNetCore.CAP/Infrastructure/WaitHandleEx.cs b/src/DotNetCore.CAP/Infrastructure/WaitHandleEx.cs index 385959f..24cfbdf 100644 --- a/src/DotNetCore.CAP/Infrastructure/WaitHandleEx.cs +++ b/src/DotNetCore.CAP/Infrastructure/WaitHandleEx.cs @@ -7,6 +7,9 @@ namespace DotNetCore.CAP.Infrastructure public static class WaitHandleEx { public static readonly AutoResetEvent PulseEvent = new AutoResetEvent(true); + public static readonly AutoResetEvent QueuePulseEvent = new AutoResetEvent(true); + public static readonly AutoResetEvent SentPulseEvent = new AutoResetEvent(true); + public static readonly AutoResetEvent ReceviedPulseEvent = new AutoResetEvent(true); public static Task WaitAnyAsync(WaitHandle handle1, WaitHandle handle2, TimeSpan timeout) { diff --git a/src/DotNetCore.CAP/Job/ComputedCronJob.cs b/src/DotNetCore.CAP/Job/ComputedCronJob.cs deleted file mode 100644 index dcfbe28..0000000 --- a/src/DotNetCore.CAP/Job/ComputedCronJob.cs +++ /dev/null @@ -1,57 +0,0 @@ -using System; -using NCrontab; - -namespace DotNetCore.CAP.Job -{ - public class ComputedCronJob - { - private readonly CronJobRegistry.Entry _entry; - - public ComputedCronJob() - { - } - - public ComputedCronJob(CronJob job) - { - Job = job; - - Schedule = CrontabSchedule.Parse(job.Cron); - if (job.TypeName != null) - { - JobType = Type.GetType(job.TypeName); - } - } - - public ComputedCronJob(CronJob job, CronJobRegistry.Entry entry) - : this(job) - { - _entry = entry; - } - - public CronJob Job { get; set; } - - public CrontabSchedule Schedule { get; set; } - - public Type JobType { get; set; } - - public DateTime Next { get; set; } - - public int Retries { get; set; } - - public DateTime FirstTry { get; set; } - - public RetryBehavior RetryBehavior => _entry.RetryBehavior; - - public void Update(DateTime baseTime) - { - Job.LastRun = baseTime; - } - - public void UpdateNext(DateTime now) - { - var next = Schedule.GetNextOccurrence(now); - var previousNext = Schedule.GetNextOccurrence(Job.LastRun); - Next = next > previousNext ? now : next; - } - } -} \ No newline at end of file diff --git a/src/DotNetCore.CAP/Job/Cron.cs b/src/DotNetCore.CAP/Job/Cron.cs deleted file mode 100644 index 9899f41..0000000 --- a/src/DotNetCore.CAP/Job/Cron.cs +++ /dev/null @@ -1,198 +0,0 @@ -using System; - -namespace DotNetCore.CAP.Job -{ - public class Cron - { - /// - /// Returns cron expression that fires every minute. - /// - public static string Minutely() - { - return "* * * * *"; - } - - /// - /// Returns cron expression that fires every hour at the first minute. - /// - public static string Hourly() - { - return Hourly(minute: 0); - } - - /// - /// Returns cron expression that fires every hour at the specified minute. - /// - /// The minute in which the schedule will be activated (0-59). - public static string Hourly(int minute) - { - return string.Format("{0} * * * *", minute); - } - - /// - /// Returns cron expression that fires every day at 00:00 UTC. - /// - public static string Daily() - { - return Daily(hour: 0); - } - - /// - /// Returns cron expression that fires every day at the first minute of - /// the specified hour in UTC. - /// - /// The hour in which the schedule will be activated (0-23). - public static string Daily(int hour) - { - return Daily(hour, minute: 0); - } - - /// - /// Returns cron expression that fires every day at the specified hour and minute - /// in UTC. - /// - /// The hour in which the schedule will be activated (0-23). - /// The minute in which the schedule will be activated (0-59). - public static string Daily(int hour, int minute) - { - return string.Format("{0} {1} * * *", minute, hour); - } - - /// - /// Returns cron expression that fires every week at Monday, 00:00 UTC. - /// - public static string Weekly() - { - return Weekly(DayOfWeek.Monday); - } - - /// - /// Returns cron expression that fires every week at 00:00 UTC of the specified - /// day of the week. - /// - /// The day of week in which the schedule will be activated. - public static string Weekly(DayOfWeek dayOfWeek) - { - return Weekly(dayOfWeek, hour: 0); - } - - /// - /// Returns cron expression that fires every week at the first minute - /// of the specified day of week and hour in UTC. - /// - /// The day of week in which the schedule will be activated. - /// The hour in which the schedule will be activated (0-23). - public static string Weekly(DayOfWeek dayOfWeek, int hour) - { - return Weekly(dayOfWeek, hour, minute: 0); - } - - /// - /// Returns cron expression that fires every week at the specified day - /// of week, hour and minute in UTC. - /// - /// The day of week in which the schedule will be activated. - /// The hour in which the schedule will be activated (0-23). - /// The minute in which the schedule will be activated (0-59). - public static string Weekly(DayOfWeek dayOfWeek, int hour, int minute) - { - return string.Format("{0} {1} * * {2}", minute, hour, (int) dayOfWeek); - } - - /// - /// Returns cron expression that fires every month at 00:00 UTC of the first - /// day of month. - /// - public static string Monthly() - { - return Monthly(day: 1); - } - - /// - /// Returns cron expression that fires every month at 00:00 UTC of the specified - /// day of month. - /// - /// The day of month in which the schedule will be activated (1-31). - public static string Monthly(int day) - { - return Monthly(day, hour: 0); - } - - /// - /// Returns cron expression that fires every month at the first minute of the - /// specified day of month and hour in UTC. - /// - /// The day of month in which the schedule will be activated (1-31). - /// The hour in which the schedule will be activated (0-23). - public static string Monthly(int day, int hour) - { - return Monthly(day, hour, minute: 0); - } - - /// - /// Returns cron expression that fires every month at the specified day of month, - /// hour and minute in UTC. - /// - /// The day of month in which the schedule will be activated (1-31). - /// The hour in which the schedule will be activated (0-23). - /// The minute in which the schedule will be activated (0-59). - public static string Monthly(int day, int hour, int minute) - { - return string.Format("{0} {1} {2} * *", minute, hour, day); - } - - /// - /// Returns cron expression that fires every year on Jan, 1st at 00:00 UTC. - /// - public static string Yearly() - { - return Yearly(month: 1); - } - - /// - /// Returns cron expression that fires every year in the first day at 00:00 UTC - /// of the specified month. - /// - /// The month in which the schedule will be activated (1-12). - public static string Yearly(int month) - { - return Yearly(month, day: 1); - } - - /// - /// Returns cron expression that fires every year at 00:00 UTC of the specified - /// month and day of month. - /// - /// The month in which the schedule will be activated (1-12). - /// The day of month in which the schedule will be activated (1-31). - public static string Yearly(int month, int day) - { - return Yearly(month, day, hour: 0); - } - - /// - /// Returns cron expression that fires every year at the first minute of the - /// specified month, day and hour in UTC. - /// - /// The month in which the schedule will be activated (1-12). - /// The day of month in which the schedule will be activated (1-31). - /// The hour in which the schedule will be activated (0-23). - public static string Yearly(int month, int day, int hour) - { - return Yearly(month, day, hour, minute: 0); - } - - /// - /// Returns cron expression that fires every year at the specified month, day, - /// hour and minute in UTC. - /// - /// The month in which the schedule will be activated (1-12). - /// The day of month in which the schedule will be activated (1-31). - /// The hour in which the schedule will be activated (0-23). - /// The minute in which the schedule will be activated (0-59). - public static string Yearly(int month, int day, int hour, int minute) - { - return $"{minute} {hour} {day} {month} *"; - } - } -} \ No newline at end of file diff --git a/src/DotNetCore.CAP/Job/CronJob.cs b/src/DotNetCore.CAP/Job/CronJob.cs deleted file mode 100644 index f05fd50..0000000 --- a/src/DotNetCore.CAP/Job/CronJob.cs +++ /dev/null @@ -1,37 +0,0 @@ -using System; - -namespace DotNetCore.CAP.Job -{ - /// - /// Represents a cron job to be executed at specified intervals of time. - /// - public class CronJob - { - public CronJob() - { - Id = Guid.NewGuid().ToString(); - } - - public CronJob(string cron) - : this() - { - Cron = cron; - } - - public CronJob(string cron, DateTime lastRun) - : this(cron) - { - LastRun = lastRun; - } - - public string Id { get; set; } - - public string Name { get; set; } - - public string TypeName { get; set; } - - public string Cron { get; set; } - - public DateTime LastRun { get; set; } - } -} \ No newline at end of file diff --git a/src/DotNetCore.CAP/Job/CronJobRegistry.Default.cs b/src/DotNetCore.CAP/Job/CronJobRegistry.Default.cs deleted file mode 100644 index ee6b294..0000000 --- a/src/DotNetCore.CAP/Job/CronJobRegistry.Default.cs +++ /dev/null @@ -1,15 +0,0 @@ -using DotNetCore.CAP.Infrastructure; -using Microsoft.Extensions.Options; - -namespace DotNetCore.CAP.Job -{ - public class DefaultCronJobRegistry : CronJobRegistry - { - public DefaultCronJobRegistry(IOptions options) - { - var options1 = options.Value; - - RegisterJob(nameof(DefaultCronJobRegistry), options1.CronExp, RetryBehavior.DefaultRetry); - } - } -} \ No newline at end of file diff --git a/src/DotNetCore.CAP/Job/CronJobRegistry.cs b/src/DotNetCore.CAP/Job/CronJobRegistry.cs deleted file mode 100644 index df0d016..0000000 --- a/src/DotNetCore.CAP/Job/CronJobRegistry.cs +++ /dev/null @@ -1,68 +0,0 @@ -using System; -using System.Collections.Generic; -using System.Reflection; -using NCrontab; - -namespace DotNetCore.CAP.Job -{ - public abstract class CronJobRegistry - { - private readonly List _entries; - - protected CronJobRegistry() - { - _entries = new List(); - } - - protected void RegisterJob(string name, string cron, RetryBehavior retryBehavior = null) - where T : IJob - { - RegisterJob(name, typeof(T), cron, retryBehavior); - } - - /// - /// Registers a cron job. - /// - /// The name of the job. - /// The job's type. - /// The cron expression to use. - /// The to use. - protected void RegisterJob(string name, Type jobType, string cron, RetryBehavior retryBehavior = null) - { - if (string.IsNullOrWhiteSpace(name)) throw new ArgumentException(nameof(cron)); - if (jobType == null) throw new ArgumentNullException(nameof(jobType)); - if (cron == null) throw new ArgumentNullException(nameof(cron)); - retryBehavior = retryBehavior ?? RetryBehavior.DefaultRetry; - - CrontabSchedule.TryParse(cron); - - if (!typeof(IJob).GetTypeInfo().IsAssignableFrom(jobType)) - { - throw new ArgumentException( - "Cron jobs should extend IJob.", nameof(jobType)); - } - - _entries.Add(new Entry(name, jobType, cron)); - } - - public Entry[] Build() => _entries.ToArray(); - - public class Entry - { - public Entry(string name, Type jobType, string cron) - { - Name = name; - JobType = jobType; - Cron = cron; - } - - public string Name { get; set; } - - public Type JobType { get; set; } - - public string Cron { get; set; } - - public RetryBehavior RetryBehavior { get; set; } - } - } -} \ No newline at end of file diff --git a/src/DotNetCore.CAP/Job/IJob.CapJob.cs b/src/DotNetCore.CAP/Job/IJob.CapJob.cs index 138281d..e93ada5 100644 --- a/src/DotNetCore.CAP/Job/IJob.CapJob.cs +++ b/src/DotNetCore.CAP/Job/IJob.CapJob.cs @@ -32,32 +32,32 @@ namespace DotNetCore.CAP.Job public async Task ExecuteAsync() { - var groupedCandidates = _selector.GetCandidatesMethodsOfGroupNameGrouped(_serviceProvider); - using (var scope = _serviceProvider.CreateScope()) - { - var provider = scope.ServiceProvider; + //var groupedCandidates = _selector.GetCandidatesMethodsOfGroupNameGrouped(_serviceProvider); + //using (var scope = _serviceProvider.CreateScope()) + //{ + // var provider = scope.ServiceProvider; - var messageStore = provider.GetService(); - var nextReceivedMessage = await messageStore.GetNextReceivedMessageToBeExcuted(); - if (nextReceivedMessage != null && groupedCandidates.ContainsKey(nextReceivedMessage.Group)) - { - try - { - await messageStore.ChangeReceivedMessageStateAsync(nextReceivedMessage, StatusName.Processing); - // If there are multiple consumers in the same group, we will take the first - var executeDescriptor = groupedCandidates[nextReceivedMessage.Group][0]; - var consumerContext = new ConsumerContext(executeDescriptor, nextReceivedMessage.ToMessageContext()); - var invoker = _consumerInvokerFactory.CreateInvoker(consumerContext); - await invoker.InvokeAsync(); - await messageStore.ChangeReceivedMessageStateAsync(nextReceivedMessage, StatusName.Succeeded); + // var messageStore = provider.GetService(); + // var nextReceivedMessage = await messageStore.GetNextReceivedMessageToBeExcuted(); + // if (nextReceivedMessage != null && groupedCandidates.ContainsKey(nextReceivedMessage.Group)) + // { + // try + // { + // await messageStore.ChangeReceivedMessageStateAsync(nextReceivedMessage, StatusName.Processing); + // // If there are multiple consumers in the same group, we will take the first + // var executeDescriptor = groupedCandidates[nextReceivedMessage.Group][0]; + // var consumerContext = new ConsumerContext(executeDescriptor, nextReceivedMessage.ToMessageContext()); + // var invoker = _consumerInvokerFactory.CreateInvoker(consumerContext); + // await invoker.InvokeAsync(); + // await messageStore.ChangeReceivedMessageStateAsync(nextReceivedMessage, StatusName.Succeeded); - } - catch (Exception ex) - { - _logger.ReceivedMessageRetryExecutingFailed(nextReceivedMessage.KeyName, ex); - } - } - } + // } + // catch (Exception ex) + // { + // _logger.ReceivedMessageRetryExecutingFailed(nextReceivedMessage.KeyName, ex); + // } + // } + //} } } } \ No newline at end of file diff --git a/src/DotNetCore.CAP/Job/IJobProcessor.CronJob.cs b/src/DotNetCore.CAP/Job/IJobProcessor.CronJob.cs deleted file mode 100644 index 2c21bf7..0000000 --- a/src/DotNetCore.CAP/Job/IJobProcessor.CronJob.cs +++ /dev/null @@ -1,170 +0,0 @@ -using System; -using System.Collections.Generic; -using System.Diagnostics; -using System.Linq; -using System.Threading.Tasks; -using Microsoft.Extensions.DependencyInjection; -using Microsoft.Extensions.Logging; - -namespace DotNetCore.CAP.Job -{ - public class CronJobProcessor : IJobProcessor - { - private readonly ILogger _logger; - private IServiceProvider _provider; - private readonly DefaultCronJobRegistry _jobRegistry; - - public CronJobProcessor( - DefaultCronJobRegistry jobRegistry, - ILogger logger, - IServiceProvider provider) - { - _jobRegistry = jobRegistry; - _logger = logger; - _provider = provider; - } - - public override string ToString() => nameof(CronJobProcessor); - - public Task ProcessAsync(ProcessingContext context) - { - if (context == null) throw new ArgumentNullException(nameof(context)); - return ProcessCoreAsync(context); - } - - private async Task ProcessCoreAsync(ProcessingContext context) - { - //var storage = context.Storage; - //var jobs = await GetJobsAsync(storage); - - var jobs = GetJobs(); - if (!jobs.Any()) - { - _logger.CronJobsNotFound(); - - // This will cancel this processor. - throw new OperationCanceledException(); - } - _logger.CronJobsScheduling(jobs); - - context.ThrowIfStopping(); - - var computedJobs = Compute(jobs, context.CronJobRegistry.Build()); - if (context.IsStopping) - { - return; - } - - await Task.WhenAll(computedJobs.Select(j => RunAsync(j, context))); - } - - private async Task RunAsync(ComputedCronJob computedJob, ProcessingContext context) - { - //var storage = context.Storage; - var retryBehavior = computedJob.RetryBehavior; - - while (!context.IsStopping) - { - var now = DateTime.UtcNow; - - var due = ComputeDue(computedJob, now); - var timeSpan = due - now; - - if (timeSpan.TotalSeconds > 0) - { - await context.WaitAsync(timeSpan); - } - - context.ThrowIfStopping(); - - using (var scopedContext = context.CreateScope()) - { - var provider = scopedContext.Provider; - - var job = provider.GetService(); - var success = true; - - try - { - var sw = Stopwatch.StartNew(); - await job.ExecuteAsync(); - sw.Stop(); - computedJob.Retries = 0; - _logger.CronJobExecuted(computedJob.Job.Name, sw.Elapsed.TotalSeconds); - } - catch (Exception ex) - { - success = false; - if (computedJob.Retries == 0) - { - computedJob.FirstTry = DateTime.UtcNow; - } - computedJob.Retries++; - _logger.CronJobFailed(computedJob.Job.Name, ex); - } - - if (success) - { - computedJob.Update(DateTime.UtcNow); - } - } - } - } - - private DateTime ComputeDue(ComputedCronJob computedJob, DateTime now) - { - computedJob.UpdateNext(now); - - var retryBehavior = computedJob.RetryBehavior ?? RetryBehavior.DefaultRetry; - var retries = computedJob.Retries; - - if (retries == 0) - { - return computedJob.Next; - } - - var realNext = computedJob.Schedule.GetNextOccurrence(now); - - if (!retryBehavior.Retry) - { - // No retry. If job failed before, we don't care, just schedule it next as usual. - return realNext; - } - - if (retries >= retryBehavior.RetryCount) - { - // Max retries. Just schedule it for the next occurance. - return realNext; - } - - // Delay a bit. - return computedJob.FirstTry.AddSeconds(retryBehavior.RetryIn(retries)); - } - - private CronJob[] GetJobs() - { - var cronJobs = new List(); - var entries = _jobRegistry.Build() ?? new CronJobRegistry.Entry[0]; - foreach (var entry in entries) - { - cronJobs.Add(new CronJob - { - Name = entry.Name, - TypeName = entry.JobType.AssemblyQualifiedName, - Cron = entry.Cron, - LastRun = DateTime.MinValue - }); - } - return cronJobs.ToArray(); - } - - private ComputedCronJob[] Compute(IEnumerable jobs, CronJobRegistry.Entry[] entries) - => jobs.Select(j => CreateComputedCronJob(j, entries)).ToArray(); - - private ComputedCronJob CreateComputedCronJob(CronJob job, CronJobRegistry.Entry[] entries) - { - var entry = entries.First(e => e.Name == job.Name); - return new ComputedCronJob(job, entry); - } - } -} \ No newline at end of file diff --git a/src/DotNetCore.CAP/Job/IJobProcessor.JobQueuer.cs b/src/DotNetCore.CAP/Job/IJobProcessor.JobQueuer.cs index d297d31..bc89d18 100644 --- a/src/DotNetCore.CAP/Job/IJobProcessor.JobQueuer.cs +++ b/src/DotNetCore.CAP/Job/IJobProcessor.JobQueuer.cs @@ -1,31 +1,31 @@ using System; using System.Threading; using System.Threading.Tasks; +using DotNetCore.CAP.Infrastructure; using DotNetCore.CAP.Job.States; using DotNetCore.CAP.Models; using Microsoft.Extensions.DependencyInjection; using Microsoft.Extensions.Logging; +using Microsoft.Extensions.Options; namespace DotNetCore.CAP.Job { public class JobQueuer : IJobProcessor { private ILogger _logger; - private JobsOptions _options; + private CapOptions _options; private IStateChanger _stateChanger; private IServiceProvider _provider; - - internal static readonly AutoResetEvent PulseEvent = new AutoResetEvent(true); private TimeSpan _pollingDelay; public JobQueuer( ILogger logger, - JobsOptions options, + IOptions options, IStateChanger stateChanger, IServiceProvider provider) { _logger = logger; - _options = options; + _options = options.Value; _stateChanger = stateChanger; _provider = provider; @@ -37,7 +37,7 @@ namespace DotNetCore.CAP.Job using (var scope = _provider.CreateScope()) { CapSentMessage sentMessage; - CapReceivedMessage receivedMessage; + // CapReceivedMessage receivedMessage; var provider = scope.ServiceProvider; var connection = provider.GetRequiredService(); @@ -57,9 +57,10 @@ namespace DotNetCore.CAP.Job } context.ThrowIfStopping(); - - DelayedJobProcessor.PulseEvent.Set(); - await WaitHandleEx.WaitAnyAsync(PulseEvent, context.CancellationToken.WaitHandle, _pollingDelay); + + WaitHandleEx.SentPulseEvent.Set(); + await WaitHandleEx.WaitAnyAsync(WaitHandleEx.QueuePulseEvent, + context.CancellationToken.WaitHandle, _pollingDelay); } } } diff --git a/src/DotNetCore.CAP/Job/IMessageJobProcessor.cs b/src/DotNetCore.CAP/Job/IMessageJobProcessor.cs new file mode 100644 index 0000000..a280c0a --- /dev/null +++ b/src/DotNetCore.CAP/Job/IMessageJobProcessor.cs @@ -0,0 +1,11 @@ +using System; +using System.Collections.Generic; +using System.Text; + +namespace DotNetCore.CAP.Job +{ + public interface IMessageJobProcessor : IJobProcessor + { + bool Waiting { get; } + } +} diff --git a/src/DotNetCore.CAP/Job/IProcessingServer.Job.cs b/src/DotNetCore.CAP/Job/IProcessingServer.Job.cs index 0bb912f..0044d31 100644 --- a/src/DotNetCore.CAP/Job/IProcessingServer.Job.cs +++ b/src/DotNetCore.CAP/Job/IProcessingServer.Job.cs @@ -17,7 +17,6 @@ namespace DotNetCore.CAP.Job private readonly IServiceProvider _provider; private readonly CancellationTokenSource _cts; private readonly CapOptions _options; - private readonly DefaultCronJobRegistry _defaultJobRegistry; private IJobProcessor[] _processors; private ProcessingContext _context; @@ -28,13 +27,11 @@ namespace DotNetCore.CAP.Job ILogger logger, ILoggerFactory loggerFactory, IServiceProvider provider, - DefaultCronJobRegistry defaultJobRegistry, IOptions options) { _logger = logger; _loggerFactory = loggerFactory; _provider = provider; - _defaultJobRegistry = defaultJobRegistry; _options = options.Value; _cts = new CancellationTokenSource(); } @@ -46,10 +43,7 @@ namespace DotNetCore.CAP.Job _processors = GetProcessors(processorCount); _logger.ServerStarting(processorCount, processorCount); - _context = new ProcessingContext( - _provider, - _defaultJobRegistry, - _cts.Token); + _context = new ProcessingContext(_provider, _cts.Token); var processorTasks = _processors .Select(InfiniteRetry) @@ -57,6 +51,31 @@ namespace DotNetCore.CAP.Job _compositeTask = Task.WhenAll(processorTasks); } + public void Pulse() + { + if (!AllProcessorsWaiting()) + { + // Some processor is still executing jobs so no need to pulse. + return; + } + + _logger.LogTrace("Pulsing the JobQueuer."); + + WaitHandleEx.QueuePulseEvent.Set(); + } + + private bool AllProcessorsWaiting() + { + foreach (var processor in _processors) + { + if (!processor.Waiting) + { + return false; + } + } + return true; + } + public void Dispose() { if (_disposed) @@ -69,7 +88,7 @@ namespace DotNetCore.CAP.Job _cts.Cancel(); try { - _compositeTask.Wait((int) TimeSpan.FromSeconds(60).TotalMilliseconds); + _compositeTask.Wait((int)TimeSpan.FromSeconds(60).TotalMilliseconds); } catch (AggregateException ex) { diff --git a/src/DotNetCore.CAP/Job/ProcessingContext.cs b/src/DotNetCore.CAP/Job/ProcessingContext.cs index 7498298..764ae80 100644 --- a/src/DotNetCore.CAP/Job/ProcessingContext.cs +++ b/src/DotNetCore.CAP/Job/ProcessingContext.cs @@ -16,24 +16,19 @@ namespace DotNetCore.CAP.Job private ProcessingContext(ProcessingContext other) { Provider = other.Provider; - CronJobRegistry = other.CronJobRegistry; CancellationToken = other.CancellationToken; } public ProcessingContext( IServiceProvider provider, - CronJobRegistry cronJobRegistry, CancellationToken cancellationToken) { Provider = provider; - CronJobRegistry = cronJobRegistry; CancellationToken = cancellationToken; } public IServiceProvider Provider { get; private set; } - public CronJobRegistry CronJobRegistry { get; private set; } - public CancellationToken CancellationToken { get; } public bool IsStopping => CancellationToken.IsCancellationRequested; diff --git a/test/DotNetCore.CAP.Test/NoopMessageStore.cs b/test/DotNetCore.CAP.Test/NoopMessageStore.cs index dfa7be4..6e70ffd 100644 --- a/test/DotNetCore.CAP.Test/NoopMessageStore.cs +++ b/test/DotNetCore.CAP.Test/NoopMessageStore.cs @@ -1,7 +1,6 @@ using System; using System.Threading; using System.Threading.Tasks; -using DotNetCore.CAP.Infrastructure; using DotNetCore.CAP.Models; namespace DotNetCore.CAP.Test @@ -14,45 +13,9 @@ namespace DotNetCore.CAP.Test throw new NotImplementedException(); } - public Task ChangeSentMessageStateAsync(CapSentMessage message, string statusName, - bool autoSaveChanges = true) - { - throw new NotImplementedException(); - } - - public Task GetNextReceivedMessageToBeExcuted() - { - throw new NotImplementedException(); - } - - public Task GetNextSentMessageToBeEnqueuedAsync() - { - throw new NotImplementedException(); - } - - public Task RemoveSentMessageAsync(CapSentMessage message) - { - throw new NotImplementedException(); - } - - public Task StoreReceivedMessageAsync(CapReceivedMessage message) - { - throw new NotImplementedException(); - } - public Task StoreSentMessageAsync(CapSentMessage message) { throw new NotImplementedException(); } - - public Task UpdateReceivedMessageAsync(CapReceivedMessage message) - { - throw new NotImplementedException(); - } - - public Task UpdateSentMessageAsync(CapSentMessage message) - { - throw new NotImplementedException(); - } } } \ No newline at end of file diff --git a/test/Shared/MessageManagerTestBase.cs b/test/Shared/MessageManagerTestBase.cs index f375bf2..e0ca62b 100644 --- a/test/Shared/MessageManagerTestBase.cs +++ b/test/Shared/MessageManagerTestBase.cs @@ -66,30 +66,30 @@ namespace DotNetCore.CAP.Test Assert.NotNull(operateResult); Assert.True(operateResult.Succeeded); - operateResult = await manager.RemoveSentMessageAsync(message); - Assert.NotNull(operateResult); - Assert.True(operateResult.Succeeded); + // operateResult = await manager.RemoveSentMessageAsync(message); + // Assert.NotNull(operateResult); + // Assert.True(operateResult.Succeeded); } - [Fact] - public async Task CanUpdateReceivedMessage() - { - if (ShouldSkipDbTests()) - { - return; - } - - var manager = CreateManager(); - var message = CreateTestReceivedMessage(); - var operateResult = await manager.StoreReceivedMessageAsync(message); - Assert.NotNull(operateResult); - Assert.True(operateResult.Succeeded); - - message.StatusName = StatusName.Processing; - operateResult = await manager.UpdateReceivedMessageAsync(message); - Assert.NotNull(operateResult); - Assert.True(operateResult.Succeeded); - } + //[Fact] + //public async Task CanUpdateReceivedMessage() + //{ + // if (ShouldSkipDbTests()) + // { + // return; + // } + + // var manager = CreateManager(); + // var message = CreateTestReceivedMessage(); + // // var operateResult = await manager.StoreReceivedMessageAsync(message); + // // Assert.NotNull(operateResult); + // // Assert.True(operateResult.Succeeded); + + // // message.StatusName = StatusName.Processing; + // // operateResult = await manager.UpdateReceivedMessageAsync(message); + // // Assert.NotNull(operateResult); + // // Assert.True(operateResult.Succeeded); + //} [Fact] public async Task CanGetNextSendMessage() @@ -105,9 +105,9 @@ namespace DotNetCore.CAP.Test Assert.NotNull(operateResult); Assert.True(operateResult.Succeeded); - var storeMessage = await manager.GetNextSentMessageToBeEnqueuedAsync(); + // var storeMessage = await manager.GetNextSentMessageToBeEnqueuedAsync(); - Assert.Equal(message, storeMessage); + // Assert.Equal(message, storeMessage); } } } \ No newline at end of file From dfcaf4476de557e5528ffef74279a1b91ea1d7c3 Mon Sep 17 00:00:00 2001 From: Savorboard Date: Wed, 12 Jul 2017 01:13:14 +0800 Subject: [PATCH 05/68] rewrite storage moudle. rewrite storage moudle. --- CAP.sln | 18 ++---------------- 1 file changed, 2 insertions(+), 16 deletions(-) diff --git a/CAP.sln b/CAP.sln index b1d9467..f3a2e1c 100644 --- a/CAP.sln +++ b/CAP.sln @@ -59,10 +59,6 @@ Project("{9A19103F-16F7-4668-BE54-9A1E7A4F7556}") = "DotNetCore.CAP.EntityFramew EndProject Project("{9A19103F-16F7-4668-BE54-9A1E7A4F7556}") = "DotNetCore.CAP.Test", "test\DotNetCore.CAP.Test\DotNetCore.CAP.Test.csproj", "{F608B509-A99B-4AC7-8227-42051DD4A578}" EndProject -Project("{9A19103F-16F7-4668-BE54-9A1E7A4F7556}") = "WebApp1", "..\..\CAPTests\WebApp1\WebApp1.csproj", "{880F8E24-5B18-43E6-A75B-8AD7B24FCBEC}" -EndProject -Project("{9A19103F-16F7-4668-BE54-9A1E7A4F7556}") = "WebApp2", "..\..\CAPTests\WebApp2\WebApp2.csproj", "{C190100E-EF0D-4C63-9189-F29D0E64D66E}" -EndProject Global GlobalSection(SolutionConfigurationPlatforms) = preSolution Debug|Any CPU = Debug|Any CPU @@ -96,15 +92,7 @@ Global {F608B509-A99B-4AC7-8227-42051DD4A578}.Debug|Any CPU.ActiveCfg = Debug|Any CPU {F608B509-A99B-4AC7-8227-42051DD4A578}.Debug|Any CPU.Build.0 = Debug|Any CPU {F608B509-A99B-4AC7-8227-42051DD4A578}.Release|Any CPU.ActiveCfg = Release|Any CPU - {F608B509-A99B-4AC7-8227-42051DD4A578}.Release|Any CPU.Build.0 = Release|Any CPU - {880F8E24-5B18-43E6-A75B-8AD7B24FCBEC}.Debug|Any CPU.ActiveCfg = Debug|Any CPU - {880F8E24-5B18-43E6-A75B-8AD7B24FCBEC}.Debug|Any CPU.Build.0 = Debug|Any CPU - {880F8E24-5B18-43E6-A75B-8AD7B24FCBEC}.Release|Any CPU.ActiveCfg = Release|Any CPU - {880F8E24-5B18-43E6-A75B-8AD7B24FCBEC}.Release|Any CPU.Build.0 = Release|Any CPU - {C190100E-EF0D-4C63-9189-F29D0E64D66E}.Debug|Any CPU.ActiveCfg = Debug|Any CPU - {C190100E-EF0D-4C63-9189-F29D0E64D66E}.Debug|Any CPU.Build.0 = Debug|Any CPU - {C190100E-EF0D-4C63-9189-F29D0E64D66E}.Release|Any CPU.ActiveCfg = Release|Any CPU - {C190100E-EF0D-4C63-9189-F29D0E64D66E}.Release|Any CPU.Build.0 = Release|Any CPU + {F608B509-A99B-4AC7-8227-42051DD4A578}.Release|Any CPU.Build.0 = Release|Any CPU EndGlobalSection GlobalSection(SolutionProperties) = preSolution HideSolutionNode = FALSE @@ -117,8 +105,6 @@ Global {C42CDE33-0878-4BA0-96F2-4CB7C8FDEAAD} = {9B2AE124-6636-4DE9-83A3-70360DABD0C4} {9961B80E-0718-4280-B2A0-271B003DE26B} = {9B2AE124-6636-4DE9-83A3-70360DABD0C4} {69370370-9873-4D6A-965D-D1E16694047D} = {C09CDAB0-6DD4-46E9-B7F3-3EF2A4741EA0} - {F608B509-A99B-4AC7-8227-42051DD4A578} = {C09CDAB0-6DD4-46E9-B7F3-3EF2A4741EA0} - {880F8E24-5B18-43E6-A75B-8AD7B24FCBEC} = {3A6B6931-A123-477A-9469-8B468B5385AF} - {C190100E-EF0D-4C63-9189-F29D0E64D66E} = {3A6B6931-A123-477A-9469-8B468B5385AF} + {F608B509-A99B-4AC7-8227-42051DD4A578} = {C09CDAB0-6DD4-46E9-B7F3-3EF2A4741EA0} EndGlobalSection EndGlobal From 9371e5597b9703b74ef930d6e2a8000fc3184ad5 Mon Sep 17 00:00:00 2001 From: yangxiaodong Date: Wed, 12 Jul 2017 18:29:54 +0800 Subject: [PATCH 06/68] rewrite storage moudle. --- CAP.sln | 3 +- samples/Sample.Kafka/AppDbContext.cs | 4 +- .../Controllers/ValuesController.cs | 2 +- samples/Sample.Kafka/Startup.cs | 10 +- .../CAP.BuilderExtensions.cs | 19 +-- .../CAP.EFOptions.cs | 20 ++++ .../CapDbContext.cs | 20 ++-- .../CapPublisherExtensions.cs | 11 +- .../EFFetchedMessage.cs | 5 + .../EFStorage.cs | 9 +- .../EFStorageConnection.cs | 112 +++++++++++------- .../FetchedMessage.cs | 2 + .../SqlServerOptions.cs | 35 ++++++ .../CAP.BuilderExtensions.cs | 2 +- ...MessageJobProcessor.RabbitJobProcessor.cs} | 5 +- .../CAP.ServiceCollectionExtensions.cs | 9 +- src/DotNetCore.CAP/IBootstrapper.Default.cs | 8 +- .../IConsumerHandler.Default.cs | 5 + src/DotNetCore.CAP/IFetchedMessage.cs | 2 + src/DotNetCore.CAP/IStorageConnection.cs | 6 +- .../Job/IAdditionalProcessor.cs | 10 ++ .../Job/IProcessingServer.Job.cs | 26 ++-- src/DotNetCore.CAP/LoggerExtensions.cs | 45 ------- .../Job/ComputedJobTest.cs | 112 +++++++++--------- .../Job/JobProcessingServerTest.cs | 4 +- 25 files changed, 271 insertions(+), 215 deletions(-) create mode 100644 src/DotNetCore.CAP.EntityFrameworkCore/SqlServerOptions.cs rename src/DotNetCore.CAP.RabbitMQ/{IProcessor.RabbitJobProcessor.cs => IMessageJobProcessor.RabbitJobProcessor.cs} (97%) create mode 100644 src/DotNetCore.CAP/Job/IAdditionalProcessor.cs diff --git a/CAP.sln b/CAP.sln index f3a2e1c..fe54719 100644 --- a/CAP.sln +++ b/CAP.sln @@ -92,7 +92,6 @@ Global {F608B509-A99B-4AC7-8227-42051DD4A578}.Debug|Any CPU.ActiveCfg = Debug|Any CPU {F608B509-A99B-4AC7-8227-42051DD4A578}.Debug|Any CPU.Build.0 = Debug|Any CPU {F608B509-A99B-4AC7-8227-42051DD4A578}.Release|Any CPU.ActiveCfg = Release|Any CPU - {F608B509-A99B-4AC7-8227-42051DD4A578}.Release|Any CPU.Build.0 = Release|Any CPU EndGlobalSection GlobalSection(SolutionProperties) = preSolution HideSolutionNode = FALSE @@ -105,6 +104,6 @@ Global {C42CDE33-0878-4BA0-96F2-4CB7C8FDEAAD} = {9B2AE124-6636-4DE9-83A3-70360DABD0C4} {9961B80E-0718-4280-B2A0-271B003DE26B} = {9B2AE124-6636-4DE9-83A3-70360DABD0C4} {69370370-9873-4D6A-965D-D1E16694047D} = {C09CDAB0-6DD4-46E9-B7F3-3EF2A4741EA0} - {F608B509-A99B-4AC7-8227-42051DD4A578} = {C09CDAB0-6DD4-46E9-B7F3-3EF2A4741EA0} + {F608B509-A99B-4AC7-8227-42051DD4A578} = {C09CDAB0-6DD4-46E9-B7F3-3EF2A4741EA0} EndGlobalSection EndGlobal diff --git a/samples/Sample.Kafka/AppDbContext.cs b/samples/Sample.Kafka/AppDbContext.cs index 361929e..8140218 100644 --- a/samples/Sample.Kafka/AppDbContext.cs +++ b/samples/Sample.Kafka/AppDbContext.cs @@ -9,11 +9,11 @@ using Microsoft.EntityFrameworkCore; namespace Sample.Kafka { - public class AppDbContext : CapDbContext + public class AppDbContext :DbContext { protected override void OnConfiguring(DbContextOptionsBuilder optionsBuilder) { - optionsBuilder.UseSqlServer("Server=DESKTOP-M9R8T31;Initial Catalog=WebApp1;User Id=sa;Password=P@ssw0rd;MultipleActiveResultSets=True"); + optionsBuilder.UseSqlServer("Server=192.168.2.206;Initial Catalog=Test;User Id=cmswuliu;Password=h7xY81agBn*Veiu3;MultipleActiveResultSets=True"); } } } diff --git a/samples/Sample.Kafka/Controllers/ValuesController.cs b/samples/Sample.Kafka/Controllers/ValuesController.cs index 1e36aff..ff42daf 100644 --- a/samples/Sample.Kafka/Controllers/ValuesController.cs +++ b/samples/Sample.Kafka/Controllers/ValuesController.cs @@ -29,7 +29,7 @@ namespace Sample.Kafka.Controllers { Console.WriteLine(person.Name); Console.WriteLine(person.Age); - + } [Route("~/send")] diff --git a/samples/Sample.Kafka/Startup.cs b/samples/Sample.Kafka/Startup.cs index aa2ff25..8de4c57 100644 --- a/samples/Sample.Kafka/Startup.cs +++ b/samples/Sample.Kafka/Startup.cs @@ -24,13 +24,17 @@ namespace Sample.Kafka // This method gets called by the runtime. Use this method to add services to the container. public void ConfigureServices(IServiceCollection services) { - services.AddDbContext(); + services.AddDbContext(); services.AddCap() - .AddEntityFrameworkStores() + .AddEntityFrameworkStores(x=> { + x.ConnectionString = "Server=192.168.2.206;Initial Catalog=Test;User Id=cmswuliu;Password=h7xY81agBn*Veiu3;MultipleActiveResultSets=True"; + }) .AddRabbitMQ(x => { - x.HostName = "localhost"; + x.HostName = "192.168.2.206"; + x.UserName = "admin"; + x.Password = "123123"; }); //.AddKafka(x => x.Servers = ""); diff --git a/src/DotNetCore.CAP.EntityFrameworkCore/CAP.BuilderExtensions.cs b/src/DotNetCore.CAP.EntityFrameworkCore/CAP.BuilderExtensions.cs index c6c0831..938cb50 100644 --- a/src/DotNetCore.CAP.EntityFrameworkCore/CAP.BuilderExtensions.cs +++ b/src/DotNetCore.CAP.EntityFrameworkCore/CAP.BuilderExtensions.cs @@ -18,7 +18,7 @@ namespace Microsoft.Extensions.DependencyInjection public static CapBuilder AddEntityFrameworkStores(this CapBuilder builder) where TContext : DbContext { - builder.Services.AddScoped>(); + //builder.Services.AddScoped>(); builder.Services.AddScoped(); builder.Services.AddScoped(); @@ -26,25 +26,26 @@ namespace Microsoft.Extensions.DependencyInjection } - public static CapBuilder AddEntityFrameworkStores(this CapBuilder builder, Action actionOptions) + public static CapBuilder AddEntityFrameworkStores(this CapBuilder builder, Action actionOptions) where TContext : DbContext { - builder.Services.AddScoped>(); + //builder.Services.AddScoped>(); builder.Services.AddSingleton(); - builder.Services.AddScoped(); + builder.Services.AddScoped(); builder.Services.Configure(actionOptions); - var efOptions = new EFOptions(); - actionOptions(efOptions); + var sqlServerOptions = new SqlServerOptions(); + actionOptions(sqlServerOptions); + builder.Services.AddSingleton(sqlServerOptions); builder.Services.AddDbContext(options => { - options.UseSqlServer(efOptions.ConnectionString, sqlOpts => + options.UseSqlServer(sqlServerOptions.ConnectionString, sqlOpts => { sqlOpts.MigrationsHistoryTable( - efOptions.MigrationsHistoryTableName, - efOptions.MigrationsHistoryTableSchema ?? efOptions.Schema); + sqlServerOptions.MigrationsHistoryTableName, + sqlServerOptions.MigrationsHistoryTableSchema ?? sqlServerOptions.Schema); }); }); diff --git a/src/DotNetCore.CAP.EntityFrameworkCore/CAP.EFOptions.cs b/src/DotNetCore.CAP.EntityFrameworkCore/CAP.EFOptions.cs index 6e2b118..df2240b 100644 --- a/src/DotNetCore.CAP.EntityFrameworkCore/CAP.EFOptions.cs +++ b/src/DotNetCore.CAP.EntityFrameworkCore/CAP.EFOptions.cs @@ -38,4 +38,24 @@ namespace DotNetCore.CAP.EntityFrameworkCore /// public string MigrationsHistoryTableName { get; set; } = DefaultMigrationsHistoryTableName; } + + //public static class CapOptionsExtensions + //{ + // public static EFOptions UseSqlServer(this CapOptions options, string connectionString) + // { + // return options.UseSqlServer(opts => + // { + // opts.ConnectionString = connectionString; + // }); + // } + + // public static EFOptions UseSqlServer(this CapOptions options, Action configure) + // { + // if (configure == null) throw new ArgumentNullException(nameof(configure)); + + // (new EFOptions(configure)); + + // return options; + // } + //} } diff --git a/src/DotNetCore.CAP.EntityFrameworkCore/CapDbContext.cs b/src/DotNetCore.CAP.EntityFrameworkCore/CapDbContext.cs index 85f0d2e..3b861d1 100644 --- a/src/DotNetCore.CAP.EntityFrameworkCore/CapDbContext.cs +++ b/src/DotNetCore.CAP.EntityFrameworkCore/CapDbContext.cs @@ -10,22 +10,19 @@ namespace DotNetCore.CAP.EntityFrameworkCore /// public class CapDbContext : DbContext { - private readonly EFOptions _efOptions; - + private SqlServerOptions _sqlServerOptions; /// /// Initializes a new instance of the . /// - public CapDbContext() { - _efOptions = new EFOptions(); - } + public CapDbContext() { } /// /// Initializes a new instance of the . /// /// The options to be used by a . - public CapDbContext(DbContextOptions options, EFOptions efOptions) + public CapDbContext(DbContextOptions options, SqlServerOptions sqlServerOptions) : base(options) { - _efOptions = efOptions; + _sqlServerOptions = sqlServerOptions; } /// @@ -51,7 +48,7 @@ namespace DotNetCore.CAP.EntityFrameworkCore /// protected override void OnModelCreating(ModelBuilder modelBuilder) { - modelBuilder.HasDefaultSchema(_efOptions.Schema); + modelBuilder.HasDefaultSchema(_sqlServerOptions.Schema); modelBuilder.Entity(b => { @@ -68,9 +65,8 @@ namespace DotNetCore.CAP.EntityFrameworkCore }); } - //protected override void OnConfiguring(DbContextOptionsBuilder optionsBuilder) - //{ - // optionsBuilder.UseSqlServer("Server=DESKTOP-M9R8T31;Initial Catalog=WebApp1;User Id=sa;Password=P@ssw0rd;MultipleActiveResultSets=True"); - //} + protected override void OnConfiguring(DbContextOptionsBuilder optionsBuilder) + { + } } } \ No newline at end of file diff --git a/src/DotNetCore.CAP.EntityFrameworkCore/CapPublisherExtensions.cs b/src/DotNetCore.CAP.EntityFrameworkCore/CapPublisherExtensions.cs index ede5cab..83faf1e 100644 --- a/src/DotNetCore.CAP.EntityFrameworkCore/CapPublisherExtensions.cs +++ b/src/DotNetCore.CAP.EntityFrameworkCore/CapPublisherExtensions.cs @@ -27,12 +27,11 @@ namespace DotNetCore.CAP var sql = "INSERT INTO [cap].[CapSentMessages] ([Id],[Added],[Content],[KeyName],[LastRun],[Retries],[StatusName])VALUES(@Id,@Added,@Content,@KeyName,@LastRun,@Retries,@StatusName)"; await connection.ExecuteAsync(sql, transaction); - - JobQueuer.PulseEvent.Set(); + WaitHandleEx.QueuePulseEvent.Set(); } - public static async Task Publish(this ICapPublisher publisher, string topic, string content, IDbConnection connection,IDbTransaction transaction) + public static async Task Publish(this ICapPublisher publisher, string topic, string content, IDbConnection connection,IDbTransaction transaction) { var message = new CapSentMessage { @@ -42,10 +41,8 @@ namespace DotNetCore.CAP }; var sql = "INSERT INTO [cap].[CapSentMessages] ([Id],[Added],[Content],[KeyName],[LastRun],[Retries],[StatusName])VALUES(@Id,@Added,@Content,@KeyName,@LastRun,@Retries,@StatusName)"; - return await connection.ExecuteAsync(sql, transaction); - - JobQueuer.PulseEvent.Set(); + await connection.ExecuteAsync(sql, transaction); + WaitHandleEx.QueuePulseEvent.Set(); } - } } \ No newline at end of file diff --git a/src/DotNetCore.CAP.EntityFrameworkCore/EFFetchedMessage.cs b/src/DotNetCore.CAP.EntityFrameworkCore/EFFetchedMessage.cs index 171b8dd..5724656 100644 --- a/src/DotNetCore.CAP.EntityFrameworkCore/EFFetchedMessage.cs +++ b/src/DotNetCore.CAP.EntityFrameworkCore/EFFetchedMessage.cs @@ -3,6 +3,7 @@ using System.Collections.Generic; using System.Data; using System.Text; using System.Threading; +using Dapper; using Microsoft.EntityFrameworkCore.Storage; namespace DotNetCore.CAP.EntityFrameworkCore @@ -16,10 +17,12 @@ namespace DotNetCore.CAP.EntityFrameworkCore private readonly object _lockObject = new object(); public EFFetchedMessage(string messageId, + int type, IDbConnection connection, IDbContextTransaction transaction) { MessageId = messageId; + Type = type; _connection = connection; _transaction = transaction; _timer = new Timer(ExecuteKeepAliveQuery, null, KeepAliveInterval, KeepAliveInterval); @@ -27,6 +30,8 @@ namespace DotNetCore.CAP.EntityFrameworkCore public string MessageId { get; } + public int Type { get; } + public void RemoveFromQueue() { lock (_lockObject) diff --git a/src/DotNetCore.CAP.EntityFrameworkCore/EFStorage.cs b/src/DotNetCore.CAP.EntityFrameworkCore/EFStorage.cs index f69b059..06b2d89 100644 --- a/src/DotNetCore.CAP.EntityFrameworkCore/EFStorage.cs +++ b/src/DotNetCore.CAP.EntityFrameworkCore/EFStorage.cs @@ -30,7 +30,14 @@ namespace DotNetCore.CAP.EntityFrameworkCore var context = provider.GetRequiredService(); _logger.LogDebug("Ensuring all migrations are applied to Jobs database."); - await context.Database.MigrateAsync(cancellationToken); + try + { + await context.Database.MigrateAsync(cancellationToken); + } + catch (Exception ex) + { + throw ex; + } } } } diff --git a/src/DotNetCore.CAP.EntityFrameworkCore/EFStorageConnection.cs b/src/DotNetCore.CAP.EntityFrameworkCore/EFStorageConnection.cs index cc302f7..3436d65 100644 --- a/src/DotNetCore.CAP.EntityFrameworkCore/EFStorageConnection.cs +++ b/src/DotNetCore.CAP.EntityFrameworkCore/EFStorageConnection.cs @@ -1,10 +1,13 @@ using System; using System.Data; +using System.Data.SqlClient; using System.Linq; using System.Threading.Tasks; +using Dapper; using DotNetCore.CAP.Infrastructure; using DotNetCore.CAP.Models; using Microsoft.EntityFrameworkCore; +using Microsoft.EntityFrameworkCore.Storage; using Microsoft.Extensions.Options; namespace DotNetCore.CAP.EntityFrameworkCore @@ -12,11 +15,11 @@ namespace DotNetCore.CAP.EntityFrameworkCore public class EFStorageConnection : IStorageConnection { private readonly CapDbContext _context; - private readonly EFOptions _options; + private readonly SqlServerOptions _options; public EFStorageConnection( CapDbContext context, - IOptions options) + IOptions options) { _context = context; _options = options.Value; @@ -24,49 +27,39 @@ namespace DotNetCore.CAP.EntityFrameworkCore public CapDbContext Context => _context; - public EFOptions Options => _options; + public SqlServerOptions Options => _options; public IStorageTransaction CreateTransaction() { return new EFStorageTransaction(this); - } + } public Task GetSentMessageAsync(string id) { return _context.CapSentMessages.FirstOrDefaultAsync(x => x.Id == id); } - public async Task FetchNextSentMessageAsync() - { - // var sql = $@" - //DELETE TOP (1) - //FROM [{_options.Schema}].[{nameof(CapDbContext.CapSentMessages)}] WITH (readpast, updlock, rowlock) - //OUTPUT DELETED.Id"; - var queueFirst = await _context.CapQueue.FirstOrDefaultAsync(); - if (queueFirst == null) - return null; - - _context.CapQueue.Remove(queueFirst); + public Task FetchNextMessageAsync() + { + var sql = $@" +DELETE TOP (1) +FROM [{_options.Schema}].[{nameof(CapDbContext.CapQueue)}] WITH (readpast, updlock, rowlock) +OUTPUT DELETED.MessageId,DELETED.[Type];"; - var connection = _context.Database.GetDbConnection(); - var transaction = _context.Database.CurrentTransaction; - transaction = transaction ?? await _context.Database.BeginTransactionAsync(IsolationLevel.ReadCommitted); - return new EFFetchedMessage(queueFirst.MessageId, connection, transaction); + return FetchNextMessageCoreAsync(sql); } - public Task GetNextSentMessageToBeEnqueuedAsync() - { - // var sql = $@" - //SELECT TOP (1) * - //FROM [{_options.Schema}].[{nameof(CapDbContext.CapSentMessages)}] WITH (readpast) - //WHERE (Due IS NULL OR Due < GETUTCDATE()) AND StateName = '{StatusName.Enqueued}'"; - - // var connection = _context.GetDbConnection(); - // var message = _context.CapSentMessages.FromSql(sql).FirstOrDefaultAsync(); + public async Task GetNextSentMessageToBeEnqueuedAsync() + { + var sql = $@" +SELECT TOP (1) * +FROM [{_options.Schema}].[{nameof(CapDbContext.CapSentMessages)}] WITH (readpast) +WHERE StateName = '{StatusName.Enqueued}'"; - var message = _context.CapSentMessages.Where(x => x.StatusName == StatusName.Enqueued).FirstOrDefaultAsync(); + var connection = _context.GetDbConnection(); + var message = (await connection.QueryAsync(sql)).FirstOrDefault(); if (message != null) { @@ -76,12 +69,12 @@ namespace DotNetCore.CAP.EntityFrameworkCore return message; } + // CapReceviedMessage + public Task StoreReceivedMessageAsync(CapReceivedMessage message) { if (message == null) throw new ArgumentNullException(nameof(message)); - message.LastRun = NormalizeDateTime(message.LastRun); - _context.Add(message); return _context.SaveChangesAsync(); } @@ -91,28 +84,59 @@ namespace DotNetCore.CAP.EntityFrameworkCore return _context.CapReceivedMessages.FirstOrDefaultAsync(x => x.Id == id); } - public Task FetchNextReceivedMessageAsync() + public async Task GetNextReceviedMessageToBeEnqueuedAsync() { - throw new NotImplementedException(); + var sql = $@" +SELECT TOP (1) * +FROM [{_options.Schema}].[{nameof(CapDbContext.CapReceivedMessages)}] WITH (readpast) +WHERE StateName = '{StatusName.Enqueued}'"; + + var connection = _context.GetDbConnection(); + var message = (await connection.QueryAsync(sql)).FirstOrDefault(); + + if (message != null) + { + _context.Attach(message); + } + + return message; } - public Task GetNextReceviedMessageToBeEnqueuedAsync() + public void Dispose() { - throw new NotImplementedException(); } - private DateTime? NormalizeDateTime(DateTime? dateTime) + private async Task FetchNextMessageCoreAsync(string sql, object args = null) { - if (!dateTime.HasValue) return dateTime; - if (dateTime == DateTime.MinValue) + FetchedMessage fetchedJob = null; + var connection = _context.GetDbConnection(); + var transaction = _context.Database.CurrentTransaction; + transaction = transaction ?? await _context.Database.BeginTransactionAsync(IsolationLevel.ReadCommitted); + + try { - return new DateTime(1754, 1, 1, 0, 0, 0, DateTimeKind.Utc); + fetchedJob = + (await connection.QueryAsync(sql, args, transaction.GetDbTransaction())) + .FirstOrDefault(); + } + catch (SqlException) + { + transaction.Dispose(); + throw; } - return dateTime; - } - public void Dispose() - { - } + if (fetchedJob == null) + { + transaction.Rollback(); + transaction.Dispose(); + return null; + } + + return new EFFetchedMessage( + fetchedJob.MessageId, + fetchedJob.Type, + connection, + transaction); + } } } diff --git a/src/DotNetCore.CAP.EntityFrameworkCore/FetchedMessage.cs b/src/DotNetCore.CAP.EntityFrameworkCore/FetchedMessage.cs index dd662e1..98dcae3 100644 --- a/src/DotNetCore.CAP.EntityFrameworkCore/FetchedMessage.cs +++ b/src/DotNetCore.CAP.EntityFrameworkCore/FetchedMessage.cs @@ -7,5 +7,7 @@ namespace DotNetCore.CAP.EntityFrameworkCore public class FetchedMessage { public string MessageId { get; set; } + + public int Type { get; set; } } } diff --git a/src/DotNetCore.CAP.EntityFrameworkCore/SqlServerOptions.cs b/src/DotNetCore.CAP.EntityFrameworkCore/SqlServerOptions.cs new file mode 100644 index 0000000..4f6532e --- /dev/null +++ b/src/DotNetCore.CAP.EntityFrameworkCore/SqlServerOptions.cs @@ -0,0 +1,35 @@ +using System; +using System.Collections.Generic; +using System.Text; + +namespace DotNetCore.CAP.EntityFrameworkCore +{ + public class SqlServerOptions + { + public const string DefaultSchema = "cap"; + public const string DefaultMigrationsHistoryTableName = "__EFMigrationsHistory"; + + /// + /// Gets or sets the database's connection string that will be used to store database entities. + /// + public string ConnectionString { get; set; } + + /// + /// Gets or sets the schema to use when creating database objects. + /// Default is . + /// + public string Schema { get; set; } = DefaultSchema; + + /// + /// Gets or sets the migrations history table's schema. + /// If this is null, will be used. + /// + public string MigrationsHistoryTableSchema { get; set; } + + /// + /// Gets or sets the migrations history table's name. + /// Default is . + /// + public string MigrationsHistoryTableName { get; set; } = DefaultMigrationsHistoryTableName; + } +} diff --git a/src/DotNetCore.CAP.RabbitMQ/CAP.BuilderExtensions.cs b/src/DotNetCore.CAP.RabbitMQ/CAP.BuilderExtensions.cs index 6c0808a..2afb79e 100644 --- a/src/DotNetCore.CAP.RabbitMQ/CAP.BuilderExtensions.cs +++ b/src/DotNetCore.CAP.RabbitMQ/CAP.BuilderExtensions.cs @@ -15,7 +15,7 @@ namespace Microsoft.Extensions.DependencyInjection builder.Services.AddSingleton(); - builder.Services.AddTransient(); + builder.Services.AddTransient(); return builder; } diff --git a/src/DotNetCore.CAP.RabbitMQ/IProcessor.RabbitJobProcessor.cs b/src/DotNetCore.CAP.RabbitMQ/IMessageJobProcessor.RabbitJobProcessor.cs similarity index 97% rename from src/DotNetCore.CAP.RabbitMQ/IProcessor.RabbitJobProcessor.cs rename to src/DotNetCore.CAP.RabbitMQ/IMessageJobProcessor.RabbitJobProcessor.cs index dd884fd..fd7e3cf 100644 --- a/src/DotNetCore.CAP.RabbitMQ/IProcessor.RabbitJobProcessor.cs +++ b/src/DotNetCore.CAP.RabbitMQ/IMessageJobProcessor.RabbitJobProcessor.cs @@ -14,7 +14,7 @@ using RabbitMQ.Client; namespace DotNetCore.CAP.RabbitMQ { - public class RabbitJobProcessor : IJobProcessor + public class RabbitJobProcessor : IMessageJobProcessor { private readonly RabbitMQOptions _rabbitMqOptions; private readonly CancellationTokenSource _cts; @@ -86,10 +86,9 @@ namespace DotNetCore.CAP.RabbitMQ using (var scopedContext = context.CreateScope()) { var provider = scopedContext.Provider; - //var messageStore = provider.GetRequiredService(); var connection = provider.GetRequiredService(); - if ((fetched = await connection.FetchNextSentMessageAsync()) != null) + if ((fetched = await connection.FetchNextMessageAsync()) != null) { using (fetched) { diff --git a/src/DotNetCore.CAP/CAP.ServiceCollectionExtensions.cs b/src/DotNetCore.CAP/CAP.ServiceCollectionExtensions.cs index bd58997..9d2cbe4 100644 --- a/src/DotNetCore.CAP/CAP.ServiceCollectionExtensions.cs +++ b/src/DotNetCore.CAP/CAP.ServiceCollectionExtensions.cs @@ -7,6 +7,7 @@ using DotNetCore.CAP.Abstractions.ModelBinding; using DotNetCore.CAP.Infrastructure; using DotNetCore.CAP.Internal; using DotNetCore.CAP.Job; +using DotNetCore.CAP.Job.States; using Microsoft.Extensions.DependencyInjection.Extensions; namespace Microsoft.Extensions.DependencyInjection @@ -49,10 +50,12 @@ namespace Microsoft.Extensions.DependencyInjection services.AddSingleton(); services.AddSingleton(); services.AddSingleton(); + services.AddSingleton(); + //Processors + services.AddTransient(); + //services.AddTransient<> - services.TryAddTransient(); - services.TryAddSingleton(); - services.TryAddTransient(); + //services.TryAddSingleton(); services.TryAddScoped(); diff --git a/src/DotNetCore.CAP/IBootstrapper.Default.cs b/src/DotNetCore.CAP/IBootstrapper.Default.cs index a1d2b87..7f25780 100644 --- a/src/DotNetCore.CAP/IBootstrapper.Default.cs +++ b/src/DotNetCore.CAP/IBootstrapper.Default.cs @@ -24,7 +24,7 @@ namespace DotNetCore.CAP public DefaultBootstrapper( ILogger logger, IOptions options, - ICapMessageStore storage, + IStorage storage, IApplicationLifetime appLifetime, IServiceProvider provider) { @@ -52,7 +52,7 @@ namespace DotNetCore.CAP protected CapOptions Options { get; } - protected ICapMessageStore Storage { get; } + protected IStorage Storage { get; } protected IEnumerable Servers { get; } @@ -65,6 +65,8 @@ namespace DotNetCore.CAP private async Task BootstrapTaskAsync() { + await Storage.InitializeAsync(_cts.Token); + if (_cts.IsCancellationRequested) return; if (_cts.IsCancellationRequested) return; @@ -98,7 +100,7 @@ namespace DotNetCore.CAP item.Dispose(); } }); - return Task.FromResult(0); + return Task.CompletedTask; } } } \ No newline at end of file diff --git a/src/DotNetCore.CAP/IConsumerHandler.Default.cs b/src/DotNetCore.CAP/IConsumerHandler.Default.cs index ff11500..fa17332 100644 --- a/src/DotNetCore.CAP/IConsumerHandler.Default.cs +++ b/src/DotNetCore.CAP/IConsumerHandler.Default.cs @@ -123,6 +123,11 @@ namespace DotNetCore.CAP return receivedMessage; } + public void Pulse() + { + throw new NotImplementedException(); + } + //private void ProcessMessage(IServiceScope serviceScope, CapReceivedMessage receivedMessage) //{ // var provider = serviceScope.ServiceProvider; diff --git a/src/DotNetCore.CAP/IFetchedMessage.cs b/src/DotNetCore.CAP/IFetchedMessage.cs index 2dc2f68..f6b4291 100644 --- a/src/DotNetCore.CAP/IFetchedMessage.cs +++ b/src/DotNetCore.CAP/IFetchedMessage.cs @@ -6,6 +6,8 @@ namespace DotNetCore.CAP { string MessageId { get; } + int Type { get; } + void RemoveFromQueue(); void Requeue(); diff --git a/src/DotNetCore.CAP/IStorageConnection.cs b/src/DotNetCore.CAP/IStorageConnection.cs index 99a48ff..da3b799 100644 --- a/src/DotNetCore.CAP/IStorageConnection.cs +++ b/src/DotNetCore.CAP/IStorageConnection.cs @@ -21,7 +21,7 @@ namespace DotNetCore.CAP /// /// Fetches the next message to be executed. /// - Task FetchNextSentMessageAsync(); + Task FetchNextMessageAsync(); /// /// Returns the next message to be enqueued. @@ -42,10 +42,6 @@ namespace DotNetCore.CAP /// The message's id. Task GetReceivedMessageAsync(string id); - /// - /// Fetches the next message to be executed. - /// - Task FetchNextReceivedMessageAsync(); /// /// Returns the next message to be enqueued. diff --git a/src/DotNetCore.CAP/Job/IAdditionalProcessor.cs b/src/DotNetCore.CAP/Job/IAdditionalProcessor.cs new file mode 100644 index 0000000..c1e79f8 --- /dev/null +++ b/src/DotNetCore.CAP/Job/IAdditionalProcessor.cs @@ -0,0 +1,10 @@ +using System; +using System.Collections.Generic; +using System.Text; + +namespace DotNetCore.CAP.Job +{ + public interface IAdditionalProcessor : IJobProcessor + { + } +} diff --git a/src/DotNetCore.CAP/Job/IProcessingServer.Job.cs b/src/DotNetCore.CAP/Job/IProcessingServer.Job.cs index 0044d31..850be3c 100644 --- a/src/DotNetCore.CAP/Job/IProcessingServer.Job.cs +++ b/src/DotNetCore.CAP/Job/IProcessingServer.Job.cs @@ -19,6 +19,7 @@ namespace DotNetCore.CAP.Job private readonly CapOptions _options; private IJobProcessor[] _processors; + private IMessageJobProcessor[] _messageProcessors; private ProcessingContext _context; private Task _compositeTask; private bool _disposed; @@ -39,14 +40,14 @@ namespace DotNetCore.CAP.Job public void Start() { var processorCount = Environment.ProcessorCount; - //processorCount = 1; + processorCount = 1; _processors = GetProcessors(processorCount); _logger.ServerStarting(processorCount, processorCount); _context = new ProcessingContext(_provider, _cts.Token); var processorTasks = _processors - .Select(InfiniteRetry) + .Select(p => InfiniteRetry(p)) .Select(p => p.ProcessAsync(_context)); _compositeTask = Task.WhenAll(processorTasks); } @@ -66,7 +67,7 @@ namespace DotNetCore.CAP.Job private bool AllProcessorsWaiting() { - foreach (var processor in _processors) + foreach (var processor in _messageProcessors) { if (!processor.Waiting) { @@ -110,21 +111,14 @@ namespace DotNetCore.CAP.Job var returnedProcessors = new List(); for (int i = 0; i < processorCount; i++) { - var processors = _provider.GetServices(); - foreach (var processor in processors) - { - if (processor is CronJobProcessor) - { - if (i == 0) // only add first cronJob - returnedProcessors.Add(processor); - } - else - { - returnedProcessors.Add(processor); - } - } + var messageProcessors = _provider.GetServices(); + _messageProcessors = messageProcessors.ToArray(); + returnedProcessors.AddRange(messageProcessors); } + returnedProcessors.Add(_provider.GetService()); + returnedProcessors.Add(_provider.GetService()); + return returnedProcessors.ToArray(); } } diff --git a/src/DotNetCore.CAP/LoggerExtensions.cs b/src/DotNetCore.CAP/LoggerExtensions.cs index 72e8399..9a4fa9e 100644 --- a/src/DotNetCore.CAP/LoggerExtensions.cs +++ b/src/DotNetCore.CAP/LoggerExtensions.cs @@ -13,11 +13,6 @@ namespace DotNetCore.CAP private static readonly Action _serverShuttingDown; private static readonly Action _expectedOperationCanceledException; - private static readonly Action _cronJobsNotFound; - private static readonly Action _cronJobsScheduling; - private static readonly Action _cronJobExecuted; - private static readonly Action _cronJobFailed; - private static readonly Action _enqueuingSentMessage; private static readonly Action _enqueuingReceivdeMessage; private static readonly Action _executingConsumerMethod; @@ -45,26 +40,6 @@ namespace DotNetCore.CAP 3, "Expected an OperationCanceledException, but found '{ExceptionMessage}'."); - _cronJobsNotFound = LoggerMessage.Define( - LogLevel.Debug, - 1, - "No cron jobs found to schedule, cancelling processing of cron jobs."); - - _cronJobsScheduling = LoggerMessage.Define( - LogLevel.Debug, - 2, - "Found {JobCount} cron job(s) to schedule."); - - _cronJobExecuted = LoggerMessage.Define( - LogLevel.Debug, - 3, - "Cron job '{JobName}' executed succesfully. Took: {Seconds} secs."); - - _cronJobFailed = LoggerMessage.Define( - LogLevel.Warning, - 4, - "Cron job '{jobName}' failed to execute."); - _enqueuingSentMessage = LoggerMessage.Define( LogLevel.Debug, 2, @@ -125,25 +100,5 @@ namespace DotNetCore.CAP { _expectedOperationCanceledException(logger, ex.Message, ex); } - - public static void CronJobsNotFound(this ILogger logger) - { - _cronJobsNotFound(logger, null); - } - - public static void CronJobsScheduling(this ILogger logger, IEnumerable jobs) - { - _cronJobsScheduling(logger, jobs.Count(), null); - } - - public static void CronJobExecuted(this ILogger logger, string name, double seconds) - { - _cronJobExecuted(logger, name, seconds, null); - } - - public static void CronJobFailed(this ILogger logger, string name, Exception ex) - { - _cronJobFailed(logger, name, ex); - } } } \ No newline at end of file diff --git a/test/DotNetCore.CAP.Test/Job/ComputedJobTest.cs b/test/DotNetCore.CAP.Test/Job/ComputedJobTest.cs index f511175..731851b 100644 --- a/test/DotNetCore.CAP.Test/Job/ComputedJobTest.cs +++ b/test/DotNetCore.CAP.Test/Job/ComputedJobTest.cs @@ -1,56 +1,56 @@ -using System; -using System.Collections.Generic; -using System.Text; -using DotNetCore.CAP.Job; -using Xunit; - -namespace DotNetCore.CAP.Test.Job -{ - public class ComputedJobTest - { - [Fact] - public void UpdateNext_LastRunNever_SchedulesNow() - { - // Arrange - var now = new DateTime(2000, 1, 1, 8, 0, 0); - var cronJob = new CronJob(Cron.Daily()); - var computed = new ComputedCronJob(cronJob); - - // Act - computed.UpdateNext(now); - - // Assert - Assert.Equal(computed.Next, now); - } - - [Fact] - public void UpdateNext_LastRun_BeforePrev_SchedulesNow() - { - // Arrange - var now = new DateTime(2000, 1, 1, 8, 0, 0); - var cronJob = new CronJob(Cron.Daily(), now.Subtract(TimeSpan.FromDays(2))); - var computed = new ComputedCronJob(cronJob); - - // Act - computed.UpdateNext(now); - - // Assert - Assert.Equal(computed.Next, now); - } - - [Fact] - public void UpdateNext_LastRun_AfterPrev_SchedulesNormal() - { - // Arrange - var now = new DateTime(2000, 1, 1, 8, 0, 0); - var cronJob = new CronJob(Cron.Daily(), now.Subtract(TimeSpan.FromSeconds(5))); - var computed = new ComputedCronJob(cronJob); - - // Act - computed.UpdateNext(now); - - // Assert - Assert.True(computed.Next > now); - } - } -} \ No newline at end of file +//using System; +//using System.Collections.Generic; +//using System.Text; +//using DotNetCore.CAP.Job; +//using Xunit; + +//namespace DotNetCore.CAP.Test.Job +//{ +// public class ComputedJobTest +// { +// [Fact] +// public void UpdateNext_LastRunNever_SchedulesNow() +// { +// // Arrange +// var now = new DateTime(2000, 1, 1, 8, 0, 0); +// var cronJob = new CronJob(Cron.Daily()); +// var computed = new ComputedCronJob(cronJob); + +// // Act +// computed.UpdateNext(now); + +// // Assert +// Assert.Equal(computed.Next, now); +// } + +// [Fact] +// public void UpdateNext_LastRun_BeforePrev_SchedulesNow() +// { +// // Arrange +// var now = new DateTime(2000, 1, 1, 8, 0, 0); +// var cronJob = new CronJob(Cron.Daily(), now.Subtract(TimeSpan.FromDays(2))); +// var computed = new ComputedCronJob(cronJob); + +// // Act +// computed.UpdateNext(now); + +// // Assert +// Assert.Equal(computed.Next, now); +// } + +// [Fact] +// public void UpdateNext_LastRun_AfterPrev_SchedulesNormal() +// { +// // Arrange +// var now = new DateTime(2000, 1, 1, 8, 0, 0); +// var cronJob = new CronJob(Cron.Daily(), now.Subtract(TimeSpan.FromSeconds(5))); +// var computed = new ComputedCronJob(cronJob); + +// // Act +// computed.UpdateNext(now); + +// // Assert +// Assert.True(computed.Next > now); +// } +// } +//} \ No newline at end of file diff --git a/test/DotNetCore.CAP.Test/Job/JobProcessingServerTest.cs b/test/DotNetCore.CAP.Test/Job/JobProcessingServerTest.cs index 50df041..1394f4a 100644 --- a/test/DotNetCore.CAP.Test/Job/JobProcessingServerTest.cs +++ b/test/DotNetCore.CAP.Test/Job/JobProcessingServerTest.cs @@ -30,13 +30,13 @@ namespace DotNetCore.CAP.Test.Job var services = new ServiceCollection(); services.AddTransient(); - services.AddTransient(); + // services.AddTransient(); services.AddLogging(); services.AddSingleton(_options); services.AddSingleton(_mockStorage.Object); _provider = services.BuildServiceProvider(); - _context = new ProcessingContext(_provider, null, _cancellationTokenSource.Token); + _context = new ProcessingContext(_provider, _cancellationTokenSource.Token); } //[Fact] From e1ec8eac77294210592d36fffa06513f15719682 Mon Sep 17 00:00:00 2001 From: yangxiaodong Date: Thu, 13 Jul 2017 15:54:26 +0800 Subject: [PATCH 07/68] refactor storage module. --- .../CapMessageStore.cs | 40 -- .../EFStorageConnection.cs | 21 +- ...IMessageJobProcessor.RabbitJobProcessor.cs | 8 +- .../RabbitMQConsumerClient.cs | 2 +- src/DotNetCore.CAP/CAP.Builder.cs | 21 - src/DotNetCore.CAP/ICapMessageStore.cs | 18 - src/DotNetCore.CAP/ICapPublisher.Default.cs | 16 +- .../IConsumerHandler.Default.cs | 4 +- .../Infrastructure/StatusName.cs | 1 + src/DotNetCore.CAP/Job/IJob.CapJob.cs | 63 --- src/DotNetCore.CAP/Job/IJob.cs | 12 - .../Job/IJobProcessor.InfiniteRetry.cs | 2 + .../Job/IJobProcessor.JobQueuer.cs | 6 +- .../Job/IProcessingServer.Job.cs | 2 +- test/DotNetCore.CAP.Test/CAP.BuilderTest.cs | 97 +---- .../Job/JobProcessingServerTest.cs | 358 +++++++++--------- test/DotNetCore.CAP.Test/NoopMessageStore.cs | 24 +- test/Shared/MessageManagerTestBase.cs | 226 +++++------ 18 files changed, 358 insertions(+), 563 deletions(-) delete mode 100644 src/DotNetCore.CAP.EntityFrameworkCore/CapMessageStore.cs delete mode 100644 src/DotNetCore.CAP/ICapMessageStore.cs delete mode 100644 src/DotNetCore.CAP/Job/IJob.CapJob.cs delete mode 100644 src/DotNetCore.CAP/Job/IJob.cs diff --git a/src/DotNetCore.CAP.EntityFrameworkCore/CapMessageStore.cs b/src/DotNetCore.CAP.EntityFrameworkCore/CapMessageStore.cs deleted file mode 100644 index ee078d5..0000000 --- a/src/DotNetCore.CAP.EntityFrameworkCore/CapMessageStore.cs +++ /dev/null @@ -1,40 +0,0 @@ -using System; -using System.Threading.Tasks; -using DotNetCore.CAP.Models; -using Microsoft.EntityFrameworkCore; - -namespace DotNetCore.CAP.EntityFrameworkCore -{ - /// - /// Represents a new instance of a persistence store for the specified message types. - /// - /// The type of the data context class used to access the store. - public class CapMessageStore : ICapMessageStore where TContext : DbContext - { - /// - /// Constructs a new instance of . - /// - /// The . - public CapMessageStore(TContext context) - { - Context = context ?? throw new ArgumentNullException(nameof(context)); - } - - public TContext Context { get; private set; } - - private DbSet SentMessages => Context.Set(); - - /// - /// Creates the specified in the cap message store. - /// - /// The message to create. - public async Task StoreSentMessageAsync(CapSentMessage message) - { - if (message == null) throw new ArgumentNullException(nameof(message)); - - Context.Add(message); - await Context.SaveChangesAsync(); - return OperateResult.Success; - } - } -} \ No newline at end of file diff --git a/src/DotNetCore.CAP.EntityFrameworkCore/EFStorageConnection.cs b/src/DotNetCore.CAP.EntityFrameworkCore/EFStorageConnection.cs index 3436d65..c9305c1 100644 --- a/src/DotNetCore.CAP.EntityFrameworkCore/EFStorageConnection.cs +++ b/src/DotNetCore.CAP.EntityFrameworkCore/EFStorageConnection.cs @@ -56,17 +56,24 @@ OUTPUT DELETED.MessageId,DELETED.[Type];"; var sql = $@" SELECT TOP (1) * FROM [{_options.Schema}].[{nameof(CapDbContext.CapSentMessages)}] WITH (readpast) -WHERE StateName = '{StatusName.Enqueued}'"; +WHERE StatusName = '{StatusName.Scheduled}'"; - var connection = _context.GetDbConnection(); - var message = (await connection.QueryAsync(sql)).FirstOrDefault(); + try + { + var connection = _context.GetDbConnection(); + var message = (await connection.QueryAsync(sql)).FirstOrDefault(); - if (message != null) + if (message != null) + { + _context.Attach(message); + } + + return message; + } + catch (Exception ex) { - _context.Attach(message); + throw; } - - return message; } // CapReceviedMessage diff --git a/src/DotNetCore.CAP.RabbitMQ/IMessageJobProcessor.RabbitJobProcessor.cs b/src/DotNetCore.CAP.RabbitMQ/IMessageJobProcessor.RabbitJobProcessor.cs index fd7e3cf..5a8ff3b 100644 --- a/src/DotNetCore.CAP.RabbitMQ/IMessageJobProcessor.RabbitJobProcessor.cs +++ b/src/DotNetCore.CAP.RabbitMQ/IMessageJobProcessor.RabbitJobProcessor.cs @@ -46,7 +46,7 @@ namespace DotNetCore.CAP.RabbitMQ public Task ProcessAsync(ProcessingContext context) { if (context == null) throw new ArgumentNullException(nameof(context)); - + System.Diagnostics.Debug.WriteLine("RabbitMQ Processor 执行: " + DateTime.Now); context.ThrowIfStopping(); return ProcessCoreAsync(context); } @@ -64,10 +64,9 @@ namespace DotNetCore.CAP.RabbitMQ if (!worked) { var token = GetTokenToWaitOn(context); - } - await WaitHandleEx.WaitAnyAsync(WaitHandleEx.SentPulseEvent, - context.CancellationToken.WaitHandle, _pollingDelay); + await WaitHandleEx.WaitAnyAsync(WaitHandleEx.SentPulseEvent, token.WaitHandle, _pollingDelay); + } } finally { @@ -92,6 +91,7 @@ namespace DotNetCore.CAP.RabbitMQ { using (fetched) { + var message = await connection.GetSentMessageAsync(fetched.MessageId); try { diff --git a/src/DotNetCore.CAP.RabbitMQ/RabbitMQConsumerClient.cs b/src/DotNetCore.CAP.RabbitMQ/RabbitMQConsumerClient.cs index adfe91d..c32e6df 100644 --- a/src/DotNetCore.CAP.RabbitMQ/RabbitMQConsumerClient.cs +++ b/src/DotNetCore.CAP.RabbitMQ/RabbitMQConsumerClient.cs @@ -56,7 +56,7 @@ namespace DotNetCore.CAP.RabbitMQ _channel.BasicConsume(_queueName, false, consumer); while (true) { - Task.Delay(timeout); + Task.Delay(timeout).Wait(); } } diff --git a/src/DotNetCore.CAP/CAP.Builder.cs b/src/DotNetCore.CAP/CAP.Builder.cs index 29d5fc5..582678a 100644 --- a/src/DotNetCore.CAP/CAP.Builder.cs +++ b/src/DotNetCore.CAP/CAP.Builder.cs @@ -46,27 +46,6 @@ namespace DotNetCore.CAP return this; } - /// - /// Add an . - /// - /// The type for the to add. - /// The current instance. - public virtual CapBuilder AddMessageStore() - where T : class, ICapMessageStore - { - return AddScoped(typeof(ICapMessageStore), typeof(T)); - } - - /// - /// Add an for process . - /// - /// The type of the job. - public virtual CapBuilder AddJobs() - where T : class, IJob - { - return AddSingleton(); - } - /// /// Add an . /// diff --git a/src/DotNetCore.CAP/ICapMessageStore.cs b/src/DotNetCore.CAP/ICapMessageStore.cs deleted file mode 100644 index 798a203..0000000 --- a/src/DotNetCore.CAP/ICapMessageStore.cs +++ /dev/null @@ -1,18 +0,0 @@ -using System.Threading.Tasks; -using DotNetCore.CAP.Infrastructure; -using DotNetCore.CAP.Models; - -namespace DotNetCore.CAP -{ - /// - /// Provides an abstraction for a store which manages CAP message. - /// - public interface ICapMessageStore - { - /// - /// Creates a new message in a store as an asynchronous operation. - /// - /// The message to create in the store. - Task StoreSentMessageAsync(CapSentMessage message); - } -} \ No newline at end of file diff --git a/src/DotNetCore.CAP/ICapPublisher.Default.cs b/src/DotNetCore.CAP/ICapPublisher.Default.cs index 334ce87..5dc0b59 100644 --- a/src/DotNetCore.CAP/ICapPublisher.Default.cs +++ b/src/DotNetCore.CAP/ICapPublisher.Default.cs @@ -11,14 +11,10 @@ namespace DotNetCore.CAP /// public class DefaultCapPublisher : ICapPublisher { - private readonly ICapMessageStore _store; - private readonly ILogger _logger; + private readonly ILogger _logger; - public DefaultCapPublisher( - ICapMessageStore store, - ILogger logger) - { - _store = store; + public DefaultCapPublisher( ILogger logger) + { _logger = logger; } @@ -50,11 +46,11 @@ namespace DotNetCore.CAP StatusName = StatusName.Enqueued }; - await _store.StoreSentMessageAsync(message); + //await _store.StoreSentMessageAsync(message); - WaitHandleEx.PulseEvent.Set(); + // WaitHandleEx.PulseEvent.Set(); - _logger.EnqueuingSentMessage(topic, content); + // _logger.EnqueuingSentMessage(topic, content); } } } \ No newline at end of file diff --git a/src/DotNetCore.CAP/IConsumerHandler.Default.cs b/src/DotNetCore.CAP/IConsumerHandler.Default.cs index fa17332..89aed8d 100644 --- a/src/DotNetCore.CAP/IConsumerHandler.Default.cs +++ b/src/DotNetCore.CAP/IConsumerHandler.Default.cs @@ -66,7 +66,7 @@ namespace DotNetCore.CAP client.Listening(_pollingDelay); } - }, _cts.Token, TaskCreationOptions.LongRunning, TaskScheduler.Current); + }, _cts.Token, TaskCreationOptions.LongRunning, TaskScheduler.Default); } _compositeTask = Task.CompletedTask; } @@ -106,7 +106,7 @@ namespace DotNetCore.CAP { var receviedMessage = StoreMessage(scope, message); client.Commit(); - // ProcessMessage(scope, receviedMessage); + // ProcessMessage(scope, receviedMessage); } }; } diff --git a/src/DotNetCore.CAP/Infrastructure/StatusName.cs b/src/DotNetCore.CAP/Infrastructure/StatusName.cs index 459c17d..2841d84 100644 --- a/src/DotNetCore.CAP/Infrastructure/StatusName.cs +++ b/src/DotNetCore.CAP/Infrastructure/StatusName.cs @@ -9,6 +9,7 @@ namespace DotNetCore.CAP.Infrastructure /// public struct StatusName { + public const string Scheduled = nameof(Scheduled); public const string Enqueued = nameof(Enqueued); public const string Processing = nameof(Processing); public const string Succeeded = nameof(Succeeded); diff --git a/src/DotNetCore.CAP/Job/IJob.CapJob.cs b/src/DotNetCore.CAP/Job/IJob.CapJob.cs deleted file mode 100644 index e93ada5..0000000 --- a/src/DotNetCore.CAP/Job/IJob.CapJob.cs +++ /dev/null @@ -1,63 +0,0 @@ -using System; -using System.Threading.Tasks; -using DotNetCore.CAP.Internal; -using Microsoft.Extensions.Logging; -using Microsoft.Extensions.DependencyInjection; -using DotNetCore.CAP.Abstractions; -using DotNetCore.CAP.Infrastructure; - -namespace DotNetCore.CAP.Job -{ - public class CapJob : IJob - { - private readonly MethodMatcherCache _selector; - private readonly IConsumerInvokerFactory _consumerInvokerFactory; - private readonly IServiceProvider _serviceProvider; - private readonly ILogger _logger; - private readonly ICapMessageStore _messageStore; - - public CapJob( - ILogger logger, - IServiceProvider serviceProvider, - IConsumerInvokerFactory consumerInvokerFactory, - ICapMessageStore messageStore, - MethodMatcherCache selector) - { - _logger = logger; - _serviceProvider = serviceProvider; - _consumerInvokerFactory = consumerInvokerFactory; - _messageStore = messageStore; - _selector = selector; - } - - public async Task ExecuteAsync() - { - //var groupedCandidates = _selector.GetCandidatesMethodsOfGroupNameGrouped(_serviceProvider); - //using (var scope = _serviceProvider.CreateScope()) - //{ - // var provider = scope.ServiceProvider; - - // var messageStore = provider.GetService(); - // var nextReceivedMessage = await messageStore.GetNextReceivedMessageToBeExcuted(); - // if (nextReceivedMessage != null && groupedCandidates.ContainsKey(nextReceivedMessage.Group)) - // { - // try - // { - // await messageStore.ChangeReceivedMessageStateAsync(nextReceivedMessage, StatusName.Processing); - // // If there are multiple consumers in the same group, we will take the first - // var executeDescriptor = groupedCandidates[nextReceivedMessage.Group][0]; - // var consumerContext = new ConsumerContext(executeDescriptor, nextReceivedMessage.ToMessageContext()); - // var invoker = _consumerInvokerFactory.CreateInvoker(consumerContext); - // await invoker.InvokeAsync(); - // await messageStore.ChangeReceivedMessageStateAsync(nextReceivedMessage, StatusName.Succeeded); - - // } - // catch (Exception ex) - // { - // _logger.ReceivedMessageRetryExecutingFailed(nextReceivedMessage.KeyName, ex); - // } - // } - //} - } - } -} \ No newline at end of file diff --git a/src/DotNetCore.CAP/Job/IJob.cs b/src/DotNetCore.CAP/Job/IJob.cs deleted file mode 100644 index 64518ad..0000000 --- a/src/DotNetCore.CAP/Job/IJob.cs +++ /dev/null @@ -1,12 +0,0 @@ -using System.Threading.Tasks; - -namespace DotNetCore.CAP.Job -{ - public interface IJob - { - /// - /// Executes the job. - /// - Task ExecuteAsync(); - } -} \ No newline at end of file diff --git a/src/DotNetCore.CAP/Job/IJobProcessor.InfiniteRetry.cs b/src/DotNetCore.CAP/Job/IJobProcessor.InfiniteRetry.cs index b8803fb..619fa0a 100644 --- a/src/DotNetCore.CAP/Job/IJobProcessor.InfiniteRetry.cs +++ b/src/DotNetCore.CAP/Job/IJobProcessor.InfiniteRetry.cs @@ -1,4 +1,5 @@ using System; +using System.Diagnostics; using System.Threading.Tasks; using Microsoft.Extensions.Logging; @@ -23,6 +24,7 @@ namespace DotNetCore.CAP.Job { while (!context.IsStopping) { + Debug.WriteLine("InfiniteRetryProcessor在开线程:" + _inner.ToString() + " : " + DateTime.Now); try { await _inner.ProcessAsync(context); diff --git a/src/DotNetCore.CAP/Job/IJobProcessor.JobQueuer.cs b/src/DotNetCore.CAP/Job/IJobProcessor.JobQueuer.cs index bc89d18..ae5a644 100644 --- a/src/DotNetCore.CAP/Job/IJobProcessor.JobQueuer.cs +++ b/src/DotNetCore.CAP/Job/IJobProcessor.JobQueuer.cs @@ -46,7 +46,8 @@ namespace DotNetCore.CAP.Job (sentMessage = await connection.GetNextSentMessageToBeEnqueuedAsync()) != null) { - var state = new EnqueuedState(); + System.Diagnostics.Debug.WriteLine("JobQueuer 执行 内部循环: " + DateTime.Now); + var state = new EnqueuedState(); using (var transaction = connection.CreateTransaction()) { @@ -56,7 +57,8 @@ namespace DotNetCore.CAP.Job } } - context.ThrowIfStopping(); + System.Diagnostics.Debug.WriteLine("JobQueuer 执行: " + DateTime.Now); + context.ThrowIfStopping(); WaitHandleEx.SentPulseEvent.Set(); await WaitHandleEx.WaitAnyAsync(WaitHandleEx.QueuePulseEvent, diff --git a/src/DotNetCore.CAP/Job/IProcessingServer.Job.cs b/src/DotNetCore.CAP/Job/IProcessingServer.Job.cs index 850be3c..4724f53 100644 --- a/src/DotNetCore.CAP/Job/IProcessingServer.Job.cs +++ b/src/DotNetCore.CAP/Job/IProcessingServer.Job.cs @@ -117,7 +117,7 @@ namespace DotNetCore.CAP.Job } returnedProcessors.Add(_provider.GetService()); - returnedProcessors.Add(_provider.GetService()); + //returnedProcessors.Add(_provider.GetService()); return returnedProcessors.ToArray(); } diff --git a/test/DotNetCore.CAP.Test/CAP.BuilderTest.cs b/test/DotNetCore.CAP.Test/CAP.BuilderTest.cs index e4810fd..7d48704 100644 --- a/test/DotNetCore.CAP.Test/CAP.BuilderTest.cs +++ b/test/DotNetCore.CAP.Test/CAP.BuilderTest.cs @@ -10,29 +10,29 @@ namespace DotNetCore.CAP.Test { public class CapBuilderTest { - [Fact] - public void CanOverrideMessageStore() - { - var services = new ServiceCollection(); - services.AddCap().AddMessageStore(); + //[Fact] + //public void CanOverrideMessageStore() + //{ + // var services = new ServiceCollection(); + // services.AddCap().AddMessageStore(); - var thingy = services.BuildServiceProvider() - .GetRequiredService() as MyMessageStore; + // var thingy = services.BuildServiceProvider() + // .GetRequiredService() as MyMessageStore; - Assert.NotNull(thingy); - } + // Assert.NotNull(thingy); + ////} - [Fact] - public void CanOverrideJobs() - { - var services = new ServiceCollection(); - services.AddCap().AddJobs(); + //[Fact] + //public void CanOverrideJobs() + //{ + // var services = new ServiceCollection(); + // services.AddCap().AddJobs(); - var thingy = services.BuildServiceProvider() - .GetRequiredService() as MyJobTest; + // var thingy = services.BuildServiceProvider() + // .GetRequiredService() as MyJobTest; - Assert.NotNull(thingy); - } + // Assert.NotNull(thingy); + //} [Fact] public void CanOverrideProducerService() @@ -58,65 +58,6 @@ namespace DotNetCore.CAP.Test { throw new NotImplementedException(); } - } - - - private class MyJobTest : IJob - { - public Task ExecuteAsync() - { - throw new NotImplementedException(); - } - } - - private class MyMessageStore : ICapMessageStore - { - public Task ChangeReceivedMessageStateAsync(CapReceivedMessage message, string statusName, - bool autoSaveChanges = true) - { - throw new NotImplementedException(); - } - - public Task ChangeSentMessageStateAsync(CapSentMessage message, string statusName, - bool autoSaveChanges = true) - { - throw new NotImplementedException(); - } - - public Task GetNextReceivedMessageToBeExcuted() - { - throw new NotImplementedException(); - } - - public Task GetNextSentMessageToBeEnqueuedAsync() - { - throw new NotImplementedException(); - } - - public Task RemoveSentMessageAsync(CapSentMessage message) - { - throw new NotImplementedException(); - } - - public Task StoreReceivedMessageAsync(CapReceivedMessage message) - { - throw new NotImplementedException(); - } - - public Task StoreSentMessageAsync(CapSentMessage message) - { - throw new NotImplementedException(); - } - - public Task UpdateReceivedMessageAsync(CapReceivedMessage message) - { - throw new NotImplementedException(); - } - - public Task UpdateSentMessageAsync(CapSentMessage message) - { - throw new NotImplementedException(); - } - } + } } } \ No newline at end of file diff --git a/test/DotNetCore.CAP.Test/Job/JobProcessingServerTest.cs b/test/DotNetCore.CAP.Test/Job/JobProcessingServerTest.cs index 1394f4a..105dd13 100644 --- a/test/DotNetCore.CAP.Test/Job/JobProcessingServerTest.cs +++ b/test/DotNetCore.CAP.Test/Job/JobProcessingServerTest.cs @@ -1,185 +1,185 @@ -using System; -using System.Collections.Generic; -using System.Text; -using System.Threading; -using System.Threading.Tasks; -using DotNetCore.CAP.Infrastructure; -using DotNetCore.CAP.Job; -using Microsoft.Extensions.DependencyInjection; -using Moq; -using Xunit; - -namespace DotNetCore.CAP.Test.Job -{ - public class JobProcessingServerTest - { - private CancellationTokenSource _cancellationTokenSource; - private ProcessingContext _context; - private CapOptions _options; - private IServiceProvider _provider; - private Mock _mockStorage; - - public JobProcessingServerTest() - { - _options = new CapOptions() - { - PollingDelay = 0 - }; - _mockStorage = new Mock(); - _cancellationTokenSource = new CancellationTokenSource(); - - var services = new ServiceCollection(); - services.AddTransient(); - // services.AddTransient(); - services.AddLogging(); - services.AddSingleton(_options); - services.AddSingleton(_mockStorage.Object); - _provider = services.BuildServiceProvider(); - - _context = new ProcessingContext(_provider, _cancellationTokenSource.Token); - } - - //[Fact] - //public async Task ProcessAsync_CancellationTokenCancelled_ThrowsImmediately() - //{ - // // Arrange - // _cancellationTokenSource.Cancel(); - // var fixture = Create(); - - // // Act - // await Assert.ThrowsAsync(() => fixture.s(_context)); - //} - - //[Fact] - //public async Task ProcessAsync() - //{ - // // Arrange - // var job = new CronJob( - // InvocationData.Serialize( - // MethodInvocation.FromExpression(() => Method())).Serialize()); - - // var mockFetchedJob = Mock.Get(Mock.Of(fj => fj.JobId == 42)); - - // _mockStorageConnection - // .Setup(m => m.FetchNextJobAsync()) - // .ReturnsAsync(mockFetchedJob.Object).Verifiable(); - - // _mockStorageConnection - // .Setup(m => m.GetJobAsync(42)) - // .ReturnsAsync(job).Verifiable(); - - // var fixture = Create(); - - // // Act - // fixture.Start(); - - // // Assert - // _mockStorageConnection.VerifyAll(); - // _mockStateChanger.Verify(m => m.ChangeState(job, It.IsAny(), It.IsAny())); - // mockFetchedJob.Verify(m => m.Requeue(), Times.Never); - // mockFetchedJob.Verify(m => m.RemoveFromQueue()); - //} - - //[Fact] - //public async Task ProcessAsync_Exception() - //{ - // // Arrange - // var job = new Job( - // InvocationData.Serialize( - // MethodInvocation.FromExpression(() => Throw())).Serialize()); - - // var mockFetchedJob = Mock.Get(Mock.Of(fj => fj.JobId == 42)); - - // _mockStorageConnection - // .Setup(m => m.FetchNextJobAsync()) - // .ReturnsAsync(mockFetchedJob.Object); - - // _mockStorageConnection - // .Setup(m => m.GetJobAsync(42)) - // .ReturnsAsync(job); - - // _mockStateChanger.Setup(m => m.ChangeState(job, It.IsAny(), It.IsAny())) - // .Throws(); - - // var fixture = Create(); - - // // Act - // await fixture.ProcessAsync(_context); - - // // Assert - // job.Retries.Should().Be(0); - // mockFetchedJob.Verify(m => m.Requeue()); - //} - - //[Fact] - //public async Task ProcessAsync_JobThrows() - //{ - // // Arrange - // var job = new Job( - // InvocationData.Serialize( - // MethodInvocation.FromExpression(() => Throw())).Serialize()); - - // var mockFetchedJob = Mock.Get(Mock.Of(fj => fj.JobId == 42)); - - // _mockStorageConnection - // .Setup(m => m.FetchNextJobAsync()) - // .ReturnsAsync(mockFetchedJob.Object).Verifiable(); - - // _mockStorageConnection - // .Setup(m => m.GetJobAsync(42)) - // .ReturnsAsync(job).Verifiable(); - - // var fixture = Create(); - - // // Act - // await fixture.ProcessAsync(_context); - - // // Assert - // job.Retries.Should().Be(1); - // _mockStorageTransaction.Verify(m => m.UpdateJob(job)); - // _mockStorageConnection.VerifyAll(); - // _mockStateChanger.Verify(m => m.ChangeState(job, It.IsAny(), It.IsAny())); - // mockFetchedJob.Verify(m => m.RemoveFromQueue()); - //} - - //[Fact] - //public async Task ProcessAsync_JobThrows_WithNoRetry() - //{ - // // Arrange - // var job = new Job( - // InvocationData.Serialize( - // MethodInvocation.FromExpression(j => j.Throw())).Serialize()); +//using System; +//using System.Collections.Generic; +//using System.Text; +//using System.Threading; +//using System.Threading.Tasks; +//using DotNetCore.CAP.Infrastructure; +//using DotNetCore.CAP.Job; +//using Microsoft.Extensions.DependencyInjection; +//using Moq; +//using Xunit; + +//namespace DotNetCore.CAP.Test.Job +//{ +// public class JobProcessingServerTest +// { +// private CancellationTokenSource _cancellationTokenSource; +// private ProcessingContext _context; +// private CapOptions _options; +// private IServiceProvider _provider; +// private Mock _mockStorage; + +// public JobProcessingServerTest() +// { +// _options = new CapOptions() +// { +// PollingDelay = 0 +// }; +// _mockStorage = new Mock(); +// _cancellationTokenSource = new CancellationTokenSource(); + +// var services = new ServiceCollection(); +// services.AddTransient(); +// // services.AddTransient(); +// services.AddLogging(); +// services.AddSingleton(_options); +// services.AddSingleton(_mockStorage.Object); +// _provider = services.BuildServiceProvider(); + +// _context = new ProcessingContext(_provider, _cancellationTokenSource.Token); +// } + +// //[Fact] +// //public async Task ProcessAsync_CancellationTokenCancelled_ThrowsImmediately() +// //{ +// // // Arrange +// // _cancellationTokenSource.Cancel(); +// // var fixture = Create(); + +// // // Act +// // await Assert.ThrowsAsync(() => fixture.s(_context)); +// //} + +// //[Fact] +// //public async Task ProcessAsync() +// //{ +// // // Arrange +// // var job = new CronJob( +// // InvocationData.Serialize( +// // MethodInvocation.FromExpression(() => Method())).Serialize()); + +// // var mockFetchedJob = Mock.Get(Mock.Of(fj => fj.JobId == 42)); + +// // _mockStorageConnection +// // .Setup(m => m.FetchNextJobAsync()) +// // .ReturnsAsync(mockFetchedJob.Object).Verifiable(); + +// // _mockStorageConnection +// // .Setup(m => m.GetJobAsync(42)) +// // .ReturnsAsync(job).Verifiable(); + +// // var fixture = Create(); + +// // // Act +// // fixture.Start(); + +// // // Assert +// // _mockStorageConnection.VerifyAll(); +// // _mockStateChanger.Verify(m => m.ChangeState(job, It.IsAny(), It.IsAny())); +// // mockFetchedJob.Verify(m => m.Requeue(), Times.Never); +// // mockFetchedJob.Verify(m => m.RemoveFromQueue()); +// //} + +// //[Fact] +// //public async Task ProcessAsync_Exception() +// //{ +// // // Arrange +// // var job = new Job( +// // InvocationData.Serialize( +// // MethodInvocation.FromExpression(() => Throw())).Serialize()); + +// // var mockFetchedJob = Mock.Get(Mock.Of(fj => fj.JobId == 42)); + +// // _mockStorageConnection +// // .Setup(m => m.FetchNextJobAsync()) +// // .ReturnsAsync(mockFetchedJob.Object); + +// // _mockStorageConnection +// // .Setup(m => m.GetJobAsync(42)) +// // .ReturnsAsync(job); + +// // _mockStateChanger.Setup(m => m.ChangeState(job, It.IsAny(), It.IsAny())) +// // .Throws(); + +// // var fixture = Create(); + +// // // Act +// // await fixture.ProcessAsync(_context); + +// // // Assert +// // job.Retries.Should().Be(0); +// // mockFetchedJob.Verify(m => m.Requeue()); +// //} + +// //[Fact] +// //public async Task ProcessAsync_JobThrows() +// //{ +// // // Arrange +// // var job = new Job( +// // InvocationData.Serialize( +// // MethodInvocation.FromExpression(() => Throw())).Serialize()); + +// // var mockFetchedJob = Mock.Get(Mock.Of(fj => fj.JobId == 42)); + +// // _mockStorageConnection +// // .Setup(m => m.FetchNextJobAsync()) +// // .ReturnsAsync(mockFetchedJob.Object).Verifiable(); + +// // _mockStorageConnection +// // .Setup(m => m.GetJobAsync(42)) +// // .ReturnsAsync(job).Verifiable(); + +// // var fixture = Create(); + +// // // Act +// // await fixture.ProcessAsync(_context); + +// // // Assert +// // job.Retries.Should().Be(1); +// // _mockStorageTransaction.Verify(m => m.UpdateJob(job)); +// // _mockStorageConnection.VerifyAll(); +// // _mockStateChanger.Verify(m => m.ChangeState(job, It.IsAny(), It.IsAny())); +// // mockFetchedJob.Verify(m => m.RemoveFromQueue()); +// //} + +// //[Fact] +// //public async Task ProcessAsync_JobThrows_WithNoRetry() +// //{ +// // // Arrange +// // var job = new Job( +// // InvocationData.Serialize( +// // MethodInvocation.FromExpression(j => j.Throw())).Serialize()); - // var mockFetchedJob = Mock.Get(Mock.Of(fj => fj.JobId == 42)); - - // _mockStorageConnection - // .Setup(m => m.FetchNextJobAsync()) - // .ReturnsAsync(mockFetchedJob.Object); +// // var mockFetchedJob = Mock.Get(Mock.Of(fj => fj.JobId == 42)); + +// // _mockStorageConnection +// // .Setup(m => m.FetchNextJobAsync()) +// // .ReturnsAsync(mockFetchedJob.Object); - // _mockStorageConnection - // .Setup(m => m.GetJobAsync(42)) - // .ReturnsAsync(job); +// // _mockStorageConnection +// // .Setup(m => m.GetJobAsync(42)) +// // .ReturnsAsync(job); - // var fixture = Create(); +// // var fixture = Create(); - // // Act - // await fixture.ProcessAsync(_context); +// // // Act +// // await fixture.ProcessAsync(_context); - // // Assert - // _mockStateChanger.Verify(m => m.ChangeState(job, It.IsAny(), It.IsAny())); - //} +// // // Assert +// // _mockStateChanger.Verify(m => m.ChangeState(job, It.IsAny(), It.IsAny())); +// //} - private JobProcessingServer Create() - => _provider.GetService(); - - //public static void Method() { } - - //public static void Throw() { throw new Exception(); } - - //private class NoRetryJob : IRetryable - //{ - // public RetryBehavior RetryBehavior => new RetryBehavior(false); - // public void Throw() { throw new Exception(); } - //} - } -} \ No newline at end of file +// private JobProcessingServer Create() +// => _provider.GetService(); + +// //public static void Method() { } + +// //public static void Throw() { throw new Exception(); } + +// //private class NoRetryJob : IRetryable +// //{ +// // public RetryBehavior RetryBehavior => new RetryBehavior(false); +// // public void Throw() { throw new Exception(); } +// //} +// } +//} \ No newline at end of file diff --git a/test/DotNetCore.CAP.Test/NoopMessageStore.cs b/test/DotNetCore.CAP.Test/NoopMessageStore.cs index 6e70ffd..97cb6a7 100644 --- a/test/DotNetCore.CAP.Test/NoopMessageStore.cs +++ b/test/DotNetCore.CAP.Test/NoopMessageStore.cs @@ -5,17 +5,17 @@ using DotNetCore.CAP.Models; namespace DotNetCore.CAP.Test { - public class NoopMessageStore : ICapMessageStore - { - public Task ChangeReceivedMessageStateAsync(CapReceivedMessage message, string statusName, - bool autoSaveChanges = true) - { - throw new NotImplementedException(); - } + //public class NoopMessageStore : ICapMessageStore + //{ + // public Task ChangeReceivedMessageStateAsync(CapReceivedMessage message, string statusName, + // bool autoSaveChanges = true) + // { + // throw new NotImplementedException(); + // } - public Task StoreSentMessageAsync(CapSentMessage message) - { - throw new NotImplementedException(); - } - } + // public Task StoreSentMessageAsync(CapSentMessage message) + // { + // throw new NotImplementedException(); + // } + //} } \ No newline at end of file diff --git a/test/Shared/MessageManagerTestBase.cs b/test/Shared/MessageManagerTestBase.cs index e0ca62b..21f641a 100644 --- a/test/Shared/MessageManagerTestBase.cs +++ b/test/Shared/MessageManagerTestBase.cs @@ -1,113 +1,113 @@ -using System; -using System.Threading.Tasks; -using DotNetCore.CAP.Infrastructure; -using DotNetCore.CAP.Models; -using Microsoft.AspNetCore.Http; -using Microsoft.Extensions.DependencyInjection; -using Microsoft.Extensions.Logging; -using Xunit; - -namespace DotNetCore.CAP.Test -{ - public abstract class MessageManagerTestBase - { - private const string NullValue = "(null)"; - - protected virtual bool ShouldSkipDbTests() - { - return false; - } - - protected virtual void SetupMessageServices(IServiceCollection services, object context = null) - { - services.AddSingleton(); - services.AddCap(); - AddMessageStore(services, context); - - services.AddSingleton>(new TestLogger()); - } - - protected virtual ICapMessageStore CreateManager(object context = null, IServiceCollection services = null, - Action configureServices = null) - { - if (services == null) - { - services = new ServiceCollection(); - } - if (context == null) - { - context = CreateTestContext(); - } - SetupMessageServices(services, context); - - configureServices?.Invoke(services); - - return services.BuildServiceProvider().GetService(); - } - - protected abstract object CreateTestContext(); - - protected abstract CapSentMessage CreateTestSentMessage(string content = ""); - protected abstract CapReceivedMessage CreateTestReceivedMessage(string content = ""); - - protected abstract void AddMessageStore(IServiceCollection services, object context = null); - - [Fact] - public async Task CanDeleteSentMessage() - { - if (ShouldSkipDbTests()) - { - return; - } - - var manager = CreateManager(); - var message = CreateTestSentMessage(); - var operateResult = await manager.StoreSentMessageAsync(message); - Assert.NotNull(operateResult); - Assert.True(operateResult.Succeeded); - - // operateResult = await manager.RemoveSentMessageAsync(message); - // Assert.NotNull(operateResult); - // Assert.True(operateResult.Succeeded); - } - - //[Fact] - //public async Task CanUpdateReceivedMessage() - //{ - // if (ShouldSkipDbTests()) - // { - // return; - // } - - // var manager = CreateManager(); - // var message = CreateTestReceivedMessage(); - // // var operateResult = await manager.StoreReceivedMessageAsync(message); - // // Assert.NotNull(operateResult); - // // Assert.True(operateResult.Succeeded); - - // // message.StatusName = StatusName.Processing; - // // operateResult = await manager.UpdateReceivedMessageAsync(message); - // // Assert.NotNull(operateResult); - // // Assert.True(operateResult.Succeeded); - //} - - [Fact] - public async Task CanGetNextSendMessage() - { - if (ShouldSkipDbTests()) - { - return; - } - var manager = CreateManager(); - var message = CreateTestSentMessage(); - - var operateResult = await manager.StoreSentMessageAsync(message); - Assert.NotNull(operateResult); - Assert.True(operateResult.Succeeded); - - // var storeMessage = await manager.GetNextSentMessageToBeEnqueuedAsync(); - - // Assert.Equal(message, storeMessage); - } - } -} \ No newline at end of file +//using System; +//using System.Threading.Tasks; +//using DotNetCore.CAP.Infrastructure; +//using DotNetCore.CAP.Models; +//using Microsoft.AspNetCore.Http; +//using Microsoft.Extensions.DependencyInjection; +//using Microsoft.Extensions.Logging; +//using Xunit; + +//namespace DotNetCore.CAP.Test +//{ +// public abstract class MessageManagerTestBase +// { +// private const string NullValue = "(null)"; + +// protected virtual bool ShouldSkipDbTests() +// { +// return false; +// } + +// protected virtual void SetupMessageServices(IServiceCollection services, object context = null) +// { +// services.AddSingleton(); +// services.AddCap(); +// AddMessageStore(services, context); + +// services.AddSingleton>(new TestLogger()); +// } + +// protected virtual ICapMessageStore CreateManager(object context = null, IServiceCollection services = null, +// Action configureServices = null) +// { +// if (services == null) +// { +// services = new ServiceCollection(); +// } +// if (context == null) +// { +// context = CreateTestContext(); +// } +// SetupMessageServices(services, context); + +// configureServices?.Invoke(services); + +// return services.BuildServiceProvider().GetService(); +// } + +// protected abstract object CreateTestContext(); + +// protected abstract CapSentMessage CreateTestSentMessage(string content = ""); +// protected abstract CapReceivedMessage CreateTestReceivedMessage(string content = ""); + +// protected abstract void AddMessageStore(IServiceCollection services, object context = null); + +// [Fact] +// public async Task CanDeleteSentMessage() +// { +// if (ShouldSkipDbTests()) +// { +// return; +// } + +// var manager = CreateManager(); +// var message = CreateTestSentMessage(); +// var operateResult = await manager.StoreSentMessageAsync(message); +// Assert.NotNull(operateResult); +// Assert.True(operateResult.Succeeded); + +// // operateResult = await manager.RemoveSentMessageAsync(message); +// // Assert.NotNull(operateResult); +// // Assert.True(operateResult.Succeeded); +// } + +// //[Fact] +// //public async Task CanUpdateReceivedMessage() +// //{ +// // if (ShouldSkipDbTests()) +// // { +// // return; +// // } + +// // var manager = CreateManager(); +// // var message = CreateTestReceivedMessage(); +// // // var operateResult = await manager.StoreReceivedMessageAsync(message); +// // // Assert.NotNull(operateResult); +// // // Assert.True(operateResult.Succeeded); + +// // // message.StatusName = StatusName.Processing; +// // // operateResult = await manager.UpdateReceivedMessageAsync(message); +// // // Assert.NotNull(operateResult); +// // // Assert.True(operateResult.Succeeded); +// //} + +// [Fact] +// public async Task CanGetNextSendMessage() +// { +// if (ShouldSkipDbTests()) +// { +// return; +// } +// var manager = CreateManager(); +// var message = CreateTestSentMessage(); + +// var operateResult = await manager.StoreSentMessageAsync(message); +// Assert.NotNull(operateResult); +// Assert.True(operateResult.Succeeded); + +// // var storeMessage = await manager.GetNextSentMessageToBeEnqueuedAsync(); + +// // Assert.Equal(message, storeMessage); +// } +// } +//} \ No newline at end of file From 6e6812a599941d165db33d6a9eb0363679f88041 Mon Sep 17 00:00:00 2001 From: yangxiaodong Date: Thu, 13 Jul 2017 18:34:44 +0800 Subject: [PATCH 08/68] refactor --- .../EFFetchedMessage.cs | 5 +- .../EFStorageTransaction.cs | 2 +- .../FetchedMessage.cs | 3 +- .../CAP.ServiceCollectionExtensions.cs | 5 +- src/DotNetCore.CAP/DotNetCore.CAP.csproj | 5 + .../IConsumerHandler.Default.cs | 2 +- src/DotNetCore.CAP/IFetchedMessage.cs | 3 +- .../IQueueExecutor.Publish.Base.cs | 105 ++++++++++++ src/DotNetCore.CAP/IQueueExecutor.Subscibe.cs | 153 ++++++++++++++++++ src/DotNetCore.CAP/IQueueExecutor.cs | 12 ++ src/DotNetCore.CAP/IQueueExecutorFactory.cs | 9 ++ .../Internal/SubscriberNotFoundException.cs | 13 ++ .../Job/IJobProcessor.JobQueuer.cs | 5 +- .../Job/IJobProcessor.MessageJob.Default.cs | 96 +++++++++++ src/DotNetCore.CAP/LoggerExtensions.cs | 61 +++++++ src/DotNetCore.CAP/Models/CapQueue.cs | 2 +- src/DotNetCore.CAP/Models/MessageType.cs | 8 + src/DotNetCore.CAP/QueueExecutorFactory.cs | 32 ++++ 18 files changed, 508 insertions(+), 13 deletions(-) create mode 100644 src/DotNetCore.CAP/IQueueExecutor.Publish.Base.cs create mode 100644 src/DotNetCore.CAP/IQueueExecutor.Subscibe.cs create mode 100644 src/DotNetCore.CAP/IQueueExecutor.cs create mode 100644 src/DotNetCore.CAP/IQueueExecutorFactory.cs create mode 100644 src/DotNetCore.CAP/Internal/SubscriberNotFoundException.cs create mode 100644 src/DotNetCore.CAP/Job/IJobProcessor.MessageJob.Default.cs create mode 100644 src/DotNetCore.CAP/Models/MessageType.cs create mode 100644 src/DotNetCore.CAP/QueueExecutorFactory.cs diff --git a/src/DotNetCore.CAP.EntityFrameworkCore/EFFetchedMessage.cs b/src/DotNetCore.CAP.EntityFrameworkCore/EFFetchedMessage.cs index 5724656..8e75f3f 100644 --- a/src/DotNetCore.CAP.EntityFrameworkCore/EFFetchedMessage.cs +++ b/src/DotNetCore.CAP.EntityFrameworkCore/EFFetchedMessage.cs @@ -4,6 +4,7 @@ using System.Data; using System.Text; using System.Threading; using Dapper; +using DotNetCore.CAP.Models; using Microsoft.EntityFrameworkCore.Storage; namespace DotNetCore.CAP.EntityFrameworkCore @@ -17,7 +18,7 @@ namespace DotNetCore.CAP.EntityFrameworkCore private readonly object _lockObject = new object(); public EFFetchedMessage(string messageId, - int type, + MessageType type, IDbConnection connection, IDbContextTransaction transaction) { @@ -30,7 +31,7 @@ namespace DotNetCore.CAP.EntityFrameworkCore public string MessageId { get; } - public int Type { get; } + public MessageType Type { get; } public void RemoveFromQueue() { diff --git a/src/DotNetCore.CAP.EntityFrameworkCore/EFStorageTransaction.cs b/src/DotNetCore.CAP.EntityFrameworkCore/EFStorageTransaction.cs index 47cb24c..ed38d9e 100644 --- a/src/DotNetCore.CAP.EntityFrameworkCore/EFStorageTransaction.cs +++ b/src/DotNetCore.CAP.EntityFrameworkCore/EFStorageTransaction.cs @@ -46,7 +46,7 @@ namespace DotNetCore.CAP.EntityFrameworkCore _connection.Context.Add(new CapQueue { MessageId = message.Id, - Type = 1 + Type = MessageType.Subscribe }); } diff --git a/src/DotNetCore.CAP.EntityFrameworkCore/FetchedMessage.cs b/src/DotNetCore.CAP.EntityFrameworkCore/FetchedMessage.cs index 98dcae3..b1827e1 100644 --- a/src/DotNetCore.CAP.EntityFrameworkCore/FetchedMessage.cs +++ b/src/DotNetCore.CAP.EntityFrameworkCore/FetchedMessage.cs @@ -1,6 +1,7 @@ using System; using System.Collections.Generic; using System.Text; +using DotNetCore.CAP.Models; namespace DotNetCore.CAP.EntityFrameworkCore { @@ -8,6 +9,6 @@ namespace DotNetCore.CAP.EntityFrameworkCore { public string MessageId { get; set; } - public int Type { get; set; } + public MessageType Type { get; set; } } } diff --git a/src/DotNetCore.CAP/CAP.ServiceCollectionExtensions.cs b/src/DotNetCore.CAP/CAP.ServiceCollectionExtensions.cs index 9d2cbe4..208b635 100644 --- a/src/DotNetCore.CAP/CAP.ServiceCollectionExtensions.cs +++ b/src/DotNetCore.CAP/CAP.ServiceCollectionExtensions.cs @@ -53,9 +53,10 @@ namespace Microsoft.Extensions.DependencyInjection services.AddSingleton(); //Processors services.AddTransient(); - //services.AddTransient<> + + services.AddSingleton(); + services.AddSingleton(); - //services.TryAddSingleton(); services.TryAddScoped(); diff --git a/src/DotNetCore.CAP/DotNetCore.CAP.csproj b/src/DotNetCore.CAP/DotNetCore.CAP.csproj index b497c57..ffbf70e 100644 --- a/src/DotNetCore.CAP/DotNetCore.CAP.csproj +++ b/src/DotNetCore.CAP/DotNetCore.CAP.csproj @@ -13,6 +13,11 @@ False + + + + + diff --git a/src/DotNetCore.CAP/IConsumerHandler.Default.cs b/src/DotNetCore.CAP/IConsumerHandler.Default.cs index 89aed8d..1322b17 100644 --- a/src/DotNetCore.CAP/IConsumerHandler.Default.cs +++ b/src/DotNetCore.CAP/IConsumerHandler.Default.cs @@ -125,7 +125,7 @@ namespace DotNetCore.CAP public void Pulse() { - throw new NotImplementedException(); + WaitHandleEx.ReceviedPulseEvent.Set(); } //private void ProcessMessage(IServiceScope serviceScope, CapReceivedMessage receivedMessage) diff --git a/src/DotNetCore.CAP/IFetchedMessage.cs b/src/DotNetCore.CAP/IFetchedMessage.cs index f6b4291..ce5897c 100644 --- a/src/DotNetCore.CAP/IFetchedMessage.cs +++ b/src/DotNetCore.CAP/IFetchedMessage.cs @@ -1,4 +1,5 @@ using System; +using DotNetCore.CAP.Models; namespace DotNetCore.CAP { @@ -6,7 +7,7 @@ namespace DotNetCore.CAP { string MessageId { get; } - int Type { get; } + MessageType Type { get; } void RemoveFromQueue(); diff --git a/src/DotNetCore.CAP/IQueueExecutor.Publish.Base.cs b/src/DotNetCore.CAP/IQueueExecutor.Publish.Base.cs new file mode 100644 index 0000000..521b9f8 --- /dev/null +++ b/src/DotNetCore.CAP/IQueueExecutor.Publish.Base.cs @@ -0,0 +1,105 @@ +using System; +using System.Collections.Generic; +using System.Diagnostics; +using System.Text; +using System.Threading.Tasks; +using DotNetCore.CAP.Job; +using DotNetCore.CAP.Job.States; +using DotNetCore.CAP.Models; +using Microsoft.Extensions.Logging; + +namespace DotNetCore.CAP +{ + public abstract class BasePublishQueueExecutor : IQueueExecutor + { + private readonly IStateChanger _stateChanger; + private readonly ILogger _logger; + + public BasePublishQueueExecutor(IStateChanger stateChanger, + ILogger logger) + { + _stateChanger = stateChanger; + _logger = logger; + } + + public abstract Task PublishAsync(string keyName, string content); + + public async Task ExecuteAsync(IStorageConnection connection, IFetchedMessage fetched) + { + using (fetched) + { + + var message = await connection.GetSentMessageAsync(fetched.MessageId); + try + { + var sp = Stopwatch.StartNew(); + await _stateChanger.ChangeStateAsync(message, new ProcessingState(), connection); + + if (message.Retries > 0) + { + _logger.JobRetrying(message.Retries); + } + var result = await PublishAsync(message.KeyName, message.Content); + sp.Stop(); + + var newState = default(IState); + if (!result.Succeeded) + { + var shouldRetry = await UpdateJobForRetryAsync(message, connection); + if (shouldRetry) + { + newState = new ScheduledState(); + _logger.JobFailedWillRetry(result.Exception); + } + else + { + newState = new FailedState(); + _logger.JobFailed(result.Exception); + } + } + else + { + newState = new SucceededState(); + } + await _stateChanger.ChangeStateAsync(message, newState, connection); + + fetched.RemoveFromQueue(); + + if (result.Succeeded) + { + _logger.JobExecuted(sp.Elapsed.TotalSeconds); + } + + return OperateResult.Success; + } + + catch (Exception ex) + { + _logger.ExceptionOccuredWhileExecutingJob(message?.KeyName, ex); + return OperateResult.Failed(ex); + } + } + } + + private async Task UpdateJobForRetryAsync(CapSentMessage message, IStorageConnection connection) + { + var retryBehavior = RetryBehavior.DefaultRetry; + + var now = DateTime.UtcNow; + var retries = ++message.Retries; + if (retries >= retryBehavior.RetryCount) + { + return false; + } + + var due = message.Added.AddSeconds(retryBehavior.RetryIn(retries)); + message.LastRun = due; + using (var transaction = connection.CreateTransaction()) + { + transaction.UpdateMessage(message); + await transaction.CommitAsync(); + } + return true; + } + } +} diff --git a/src/DotNetCore.CAP/IQueueExecutor.Subscibe.cs b/src/DotNetCore.CAP/IQueueExecutor.Subscibe.cs new file mode 100644 index 0000000..31cc863 --- /dev/null +++ b/src/DotNetCore.CAP/IQueueExecutor.Subscibe.cs @@ -0,0 +1,153 @@ +using System; +using System.Collections.Generic; +using System.Diagnostics; +using System.Text; +using System.Threading; +using System.Threading.Tasks; +using DotNetCore.CAP.Abstractions; +using DotNetCore.CAP.Infrastructure; +using DotNetCore.CAP.Internal; +using DotNetCore.CAP.Job; +using DotNetCore.CAP.Job.States; +using DotNetCore.CAP.Models; +using Microsoft.Extensions.Logging; + +namespace DotNetCore.CAP +{ + public class SubscibeQueueExecutor : IQueueExecutor + { + private readonly IConsumerInvokerFactory _consumerInvokerFactory; + private readonly IConsumerClientFactory _consumerClientFactory; + private readonly IStateChanger _stateChanger; + private readonly ILogger _logger; + + private readonly MethodMatcherCache _selector; + private readonly CapOptions _options; + + public SubscibeQueueExecutor( + IStateChanger stateChanger, + MethodMatcherCache selector, + IConsumerInvokerFactory consumerInvokerFactory, + IConsumerClientFactory consumerClientFactory, + ILogger logger) + { + _selector = selector; + _consumerInvokerFactory = consumerInvokerFactory; + _consumerClientFactory = consumerClientFactory; + _stateChanger = stateChanger; + _logger = logger; + } + + public async Task ExecuteAsync(IStorageConnection connection, IFetchedMessage fetched) + { + using (fetched) + { + var message = await connection.GetReceivedMessageAsync(fetched.MessageId); + try + { + var sp = Stopwatch.StartNew(); + await _stateChanger.ChangeStateAsync(message, new ProcessingState(), connection); + + if (message.Retries > 0) + { + _logger.JobRetrying(message.Retries); + } + var result = await ExecuteSubscribeAsync(message); + sp.Stop(); + + var newState = default(IState); + if (!result.Succeeded) + { + var shouldRetry = await UpdateJobForRetryAsync(message, connection); + if (shouldRetry) + { + newState = new ScheduledState(); + _logger.JobFailedWillRetry(result.Exception); + } + else + { + newState = new FailedState(); + _logger.JobFailed(result.Exception); + } + } + else + { + newState = new SucceededState(); + } + await _stateChanger.ChangeStateAsync(message, newState, connection); + + fetched.RemoveFromQueue(); + + if (result.Succeeded) + { + _logger.JobExecuted(sp.Elapsed.TotalSeconds); + } + + return OperateResult.Success; + } + catch (SubscriberNotFoundException ex) + { + _logger.LogError(ex.Message); + return OperateResult.Failed(ex); + } + catch (Exception ex) + { + _logger.ExceptionOccuredWhileExecutingJob(message?.KeyName, ex); + return OperateResult.Failed(ex); + } + } + } + + protected virtual async Task ExecuteSubscribeAsync(CapReceivedMessage receivedMessage) + { + try + { + var executeDescriptorGroup = _selector.GetTopicExector(receivedMessage.KeyName); + + if (!executeDescriptorGroup.ContainsKey(receivedMessage.Group)) + { + throw new SubscriberNotFoundException(receivedMessage.KeyName + " has not been found."); + } + + // If there are multiple consumers in the same group, we will take the first + var executeDescriptor = executeDescriptorGroup[receivedMessage.Group][0]; + var consumerContext = new ConsumerContext(executeDescriptor, receivedMessage.ToMessageContext()); + + await _consumerInvokerFactory.CreateInvoker(consumerContext).InvokeAsync(); + + return OperateResult.Success; + } + catch (SubscriberNotFoundException ex) + { + throw ex; + } + catch (Exception ex) + { + _logger.ConsumerMethodExecutingFailed($"Group:{receivedMessage.Group}, Topic:{receivedMessage.KeyName}", ex); + return OperateResult.Failed(ex); + } + } + + private async Task UpdateJobForRetryAsync(CapReceivedMessage message, IStorageConnection connection) + { + var retryBehavior = RetryBehavior.DefaultRetry; + + var now = DateTime.UtcNow; + var retries = ++message.Retries; + if (retries >= retryBehavior.RetryCount) + { + return false; + } + + var due = message.Added.AddSeconds(retryBehavior.RetryIn(retries)); + message.LastRun = due; + using (var transaction = connection.CreateTransaction()) + { + transaction.UpdateMessage(message); + await transaction.CommitAsync(); + } + return true; + } + + } +} diff --git a/src/DotNetCore.CAP/IQueueExecutor.cs b/src/DotNetCore.CAP/IQueueExecutor.cs new file mode 100644 index 0000000..7135eed --- /dev/null +++ b/src/DotNetCore.CAP/IQueueExecutor.cs @@ -0,0 +1,12 @@ +using System; +using System.Collections.Generic; +using System.Text; +using System.Threading.Tasks; + +namespace DotNetCore.CAP +{ + public interface IQueueExecutor + { + Task ExecuteAsync(IStorageConnection connection, IFetchedMessage message); + } +} diff --git a/src/DotNetCore.CAP/IQueueExecutorFactory.cs b/src/DotNetCore.CAP/IQueueExecutorFactory.cs new file mode 100644 index 0000000..5b46ac6 --- /dev/null +++ b/src/DotNetCore.CAP/IQueueExecutorFactory.cs @@ -0,0 +1,9 @@ +using DotNetCore.CAP.Models; + +namespace DotNetCore.CAP +{ + public interface IQueueExecutorFactory + { + IQueueExecutor GetInstance(MessageType messageType); + } +} \ No newline at end of file diff --git a/src/DotNetCore.CAP/Internal/SubscriberNotFoundException.cs b/src/DotNetCore.CAP/Internal/SubscriberNotFoundException.cs new file mode 100644 index 0000000..4bf9844 --- /dev/null +++ b/src/DotNetCore.CAP/Internal/SubscriberNotFoundException.cs @@ -0,0 +1,13 @@ +using System; +namespace DotNetCore.CAP.Internal +{ + public class SubscriberNotFoundException : Exception + { + public SubscriberNotFoundException() { } + + public SubscriberNotFoundException(string message) : base(message) { } + + public SubscriberNotFoundException(string message, Exception inner) : + base(message, inner) { } + } +} diff --git a/src/DotNetCore.CAP/Job/IJobProcessor.JobQueuer.cs b/src/DotNetCore.CAP/Job/IJobProcessor.JobQueuer.cs index ae5a644..8973c17 100644 --- a/src/DotNetCore.CAP/Job/IJobProcessor.JobQueuer.cs +++ b/src/DotNetCore.CAP/Job/IJobProcessor.JobQueuer.cs @@ -37,7 +37,6 @@ namespace DotNetCore.CAP.Job using (var scope = _provider.CreateScope()) { CapSentMessage sentMessage; - // CapReceivedMessage receivedMessage; var provider = scope.ServiceProvider; var connection = provider.GetRequiredService(); @@ -46,7 +45,6 @@ namespace DotNetCore.CAP.Job (sentMessage = await connection.GetNextSentMessageToBeEnqueuedAsync()) != null) { - System.Diagnostics.Debug.WriteLine("JobQueuer 执行 内部循环: " + DateTime.Now); var state = new EnqueuedState(); using (var transaction = connection.CreateTransaction()) @@ -54,10 +52,9 @@ namespace DotNetCore.CAP.Job _stateChanger.ChangeState(sentMessage, state, transaction); await transaction.CommitAsync(); } - } + } } - System.Diagnostics.Debug.WriteLine("JobQueuer 执行: " + DateTime.Now); context.ThrowIfStopping(); WaitHandleEx.SentPulseEvent.Set(); diff --git a/src/DotNetCore.CAP/Job/IJobProcessor.MessageJob.Default.cs b/src/DotNetCore.CAP/Job/IJobProcessor.MessageJob.Default.cs new file mode 100644 index 0000000..e880c36 --- /dev/null +++ b/src/DotNetCore.CAP/Job/IJobProcessor.MessageJob.Default.cs @@ -0,0 +1,96 @@ +using System; +using System.Threading; +using System.Threading.Tasks; +using DotNetCore.CAP.Infrastructure; +using Microsoft.Extensions.DependencyInjection; +using Microsoft.Extensions.Logging; +using Microsoft.Extensions.Options; + +namespace DotNetCore.CAP.Job +{ + public class DefaultMessageJobProcessor : IMessageJobProcessor + { + private readonly IQueueExecutorFactory _queueExecutorFactory; + private readonly IServiceProvider _provider; + private readonly ILogger _logger; + + private readonly CancellationTokenSource _cts; + private readonly TimeSpan _pollingDelay; + + internal static readonly AutoResetEvent PulseEvent = new AutoResetEvent(true); + + public DefaultMessageJobProcessor( + IServiceProvider provider, + IQueueExecutorFactory queueExecutorFactory, + IOptions capOptions, + ILogger logger) + { + _logger = logger; + _queueExecutorFactory = queueExecutorFactory; + _provider = provider; + _cts = new CancellationTokenSource(); + _pollingDelay = TimeSpan.FromSeconds(capOptions.Value.PollingDelay); + } + + public bool Waiting { get; private set; } + + public Task ProcessAsync(ProcessingContext context) + { + if (context == null) + throw new ArgumentNullException(nameof(context)); + + context.ThrowIfStopping(); + + return ProcessCoreAsync(context); + } + + public async Task ProcessCoreAsync(ProcessingContext context) + { + try + { + _logger.LogInformation("BaseMessageJobProcessor processing ..."); + + var worked = await Step(context); + + context.ThrowIfStopping(); + + Waiting = true; + + if (!worked) + { + var token = GetTokenToWaitOn(context); + await WaitHandleEx.WaitAnyAsync(PulseEvent, token.WaitHandle, _pollingDelay); + } + } + finally + { + Waiting = false; + } + } + + protected virtual CancellationToken GetTokenToWaitOn(ProcessingContext context) + { + return context.CancellationToken; + } + + private async Task Step(ProcessingContext context) + { + var fetched = default(IFetchedMessage); + using (var scopedContext = context.CreateScope()) + { + var provider = scopedContext.Provider; + var connection = provider.GetRequiredService(); + + if ((fetched = await connection.FetchNextMessageAsync()) != null) + { + using (fetched) + { + var queueExecutor = _queueExecutorFactory.GetInstance(fetched.Type); + await queueExecutor.ExecuteAsync(connection, fetched); + } + } + } + return fetched != null; + } + } +} diff --git a/src/DotNetCore.CAP/LoggerExtensions.cs b/src/DotNetCore.CAP/LoggerExtensions.cs index 9a4fa9e..0d1894a 100644 --- a/src/DotNetCore.CAP/LoggerExtensions.cs +++ b/src/DotNetCore.CAP/LoggerExtensions.cs @@ -18,6 +18,12 @@ namespace DotNetCore.CAP private static readonly Action _executingConsumerMethod; private static readonly Action _receivedMessageRetryExecuting; + private static Action _jobFailed; + private static Action _jobFailedWillRetry; + private static Action _jobExecuted; + private static Action _jobRetrying; + private static Action _exceptionOccuredWhileExecutingJob; + static LoggerExtensions() { _serverStarting = LoggerMessage.Define( @@ -59,8 +65,58 @@ namespace DotNetCore.CAP LogLevel.Error, 5, "Received message topic method '{topicName}' failed to execute."); + + + _jobRetrying = LoggerMessage.Define( + LogLevel.Debug, + 3, + "Retrying a job: {Retries}..."); + + _jobExecuted = LoggerMessage.Define( + LogLevel.Debug, + 4, + "Job executed. Took: {Seconds} secs."); + + _jobFailed = LoggerMessage.Define( + LogLevel.Warning, + 1, + "Job failed to execute."); + + _jobFailedWillRetry = LoggerMessage.Define( + LogLevel.Warning, + 2, + "Job failed to execute. Will retry."); + + _exceptionOccuredWhileExecutingJob = LoggerMessage.Define( + LogLevel.Error, + 6, + "An exception occured while trying to execute a job: '{JobId}'. " + + "Requeuing for another retry."); + } + + public static void JobFailed(this ILogger logger, Exception ex) + { + _jobFailed(logger, ex); } + public static void JobFailedWillRetry(this ILogger logger, Exception ex) + { + _jobFailedWillRetry(logger, ex); + } + + + public static void JobRetrying(this ILogger logger, int retries) + { + _jobRetrying(logger, retries, null); + } + + + public static void JobExecuted(this ILogger logger, double seconds) + { + _jobExecuted(logger, seconds, null); + } + + public static void ConsumerMethodExecutingFailed(this ILogger logger, string methodName, Exception ex) { _executingConsumerMethod(logger, methodName, ex); @@ -100,5 +156,10 @@ namespace DotNetCore.CAP { _expectedOperationCanceledException(logger, ex.Message, ex); } + + public static void ExceptionOccuredWhileExecutingJob(this ILogger logger, string jobId, Exception ex) + { + _exceptionOccuredWhileExecutingJob(logger, jobId, ex); + } } } \ No newline at end of file diff --git a/src/DotNetCore.CAP/Models/CapQueue.cs b/src/DotNetCore.CAP/Models/CapQueue.cs index bb64de1..229ecef 100644 --- a/src/DotNetCore.CAP/Models/CapQueue.cs +++ b/src/DotNetCore.CAP/Models/CapQueue.cs @@ -9,6 +9,6 @@ /// /// 0 is CapSentMessage, 1 is CapReceviedMessage /// - public int Type { get; set; } + public MessageType Type { get; set; } } } diff --git a/src/DotNetCore.CAP/Models/MessageType.cs b/src/DotNetCore.CAP/Models/MessageType.cs new file mode 100644 index 0000000..1ddfc74 --- /dev/null +++ b/src/DotNetCore.CAP/Models/MessageType.cs @@ -0,0 +1,8 @@ +namespace DotNetCore.CAP.Models +{ + public enum MessageType + { + Publish, + Subscribe + } +} diff --git a/src/DotNetCore.CAP/QueueExecutorFactory.cs b/src/DotNetCore.CAP/QueueExecutorFactory.cs new file mode 100644 index 0000000..1c71e93 --- /dev/null +++ b/src/DotNetCore.CAP/QueueExecutorFactory.cs @@ -0,0 +1,32 @@ +using System; +using System.Linq; +using System.Reflection; +using DotNetCore.CAP.Models; +using Microsoft.Extensions.DependencyInjection; + +namespace DotNetCore.CAP +{ + public class QueueExecutorFactory : IQueueExecutorFactory + { + private readonly IServiceProvider _serviceProvider; + + public QueueExecutorFactory(IServiceProvider serviceProvider) + { + _serviceProvider = serviceProvider; + } + + public IQueueExecutor GetInstance(MessageType messageType) + { + var _queueExectors = _serviceProvider.GetServices(); + + if (messageType== MessageType.Publish) + { + return _queueExectors.FirstOrDefault(x => typeof(BasePublishQueueExecutor).IsAssignableFrom(x.GetType())); + } + else + { + return _queueExectors.FirstOrDefault(x => !typeof(BasePublishQueueExecutor).IsAssignableFrom(x.GetType())); + } + } + } +} From 2825cceaa67f45ad8f529f2b72441b34cbe6b799 Mon Sep 17 00:00:00 2001 From: Savorboard Date: Fri, 14 Jul 2017 00:26:22 +0800 Subject: [PATCH 09/68] rename namespace. --- .../IAdditionalProcessor.cs | 3 +- .../IJobProcessor.InfiniteRetry.cs | 9 +-- .../IJobProcessor.MessageJob.Default.cs | 2 +- .../IJobProcessor.PublishQueuer.cs} | 17 +++-- .../IJobProcessor.SubscribeQueuer.cs | 68 +++++++++++++++++++ .../{Job => Processor}/IJobProcessor.cs | 2 +- .../IMessageJobProcessor.cs | 2 +- .../IProcessingServer.Cap.cs} | 53 ++++++++------- .../{Job => Processor}/ProcessingContext.cs | 2 +- .../{Job => Processor}/RetryBehavior.cs | 2 +- .../States/IState.Enqueued.cs | 2 +- .../States/IState.Failed.cs | 2 +- .../States/IState.Processing.cs | 2 +- .../States/IState.Scheduled.cs | 2 +- .../States/IState.Succeeded.cs | 2 +- .../{Job => Processor}/States/IState.cs | 2 +- .../States/IStateChanger.Default.cs | 2 +- .../States/IStateChanger.Extensions.cs | 2 +- .../States/IStateChanger.cs | 2 +- 19 files changed, 123 insertions(+), 55 deletions(-) rename src/DotNetCore.CAP/{Job => Processor}/IAdditionalProcessor.cs (80%) rename src/DotNetCore.CAP/{Job => Processor}/IJobProcessor.InfiniteRetry.cs (73%) rename src/DotNetCore.CAP/{Job => Processor}/IJobProcessor.MessageJob.Default.cs (98%) rename src/DotNetCore.CAP/{Job/IJobProcessor.JobQueuer.cs => Processor/IJobProcessor.PublishQueuer.cs} (79%) create mode 100644 src/DotNetCore.CAP/Processor/IJobProcessor.SubscribeQueuer.cs rename src/DotNetCore.CAP/{Job => Processor}/IJobProcessor.cs (79%) rename src/DotNetCore.CAP/{Job => Processor}/IMessageJobProcessor.cs (83%) rename src/DotNetCore.CAP/{Job/IProcessingServer.Job.cs => Processor/IProcessingServer.Cap.cs} (78%) rename src/DotNetCore.CAP/{Job => Processor}/ProcessingContext.cs (97%) rename src/DotNetCore.CAP/{Job => Processor}/RetryBehavior.cs (98%) rename src/DotNetCore.CAP/{Job => Processor}/States/IState.Enqueued.cs (92%) rename src/DotNetCore.CAP/{Job => Processor}/States/IState.Failed.cs (91%) rename src/DotNetCore.CAP/{Job => Processor}/States/IState.Processing.cs (91%) rename src/DotNetCore.CAP/{Job => Processor}/States/IState.Scheduled.cs (91%) rename src/DotNetCore.CAP/{Job => Processor}/States/IState.Succeeded.cs (91%) rename src/DotNetCore.CAP/{Job => Processor}/States/IState.cs (88%) rename src/DotNetCore.CAP/{Job => Processor}/States/IStateChanger.Default.cs (96%) rename src/DotNetCore.CAP/{Job => Processor}/States/IStateChanger.Extensions.cs (95%) rename src/DotNetCore.CAP/{Job => Processor}/States/IStateChanger.cs (86%) diff --git a/src/DotNetCore.CAP/Job/IAdditionalProcessor.cs b/src/DotNetCore.CAP/Processor/IAdditionalProcessor.cs similarity index 80% rename from src/DotNetCore.CAP/Job/IAdditionalProcessor.cs rename to src/DotNetCore.CAP/Processor/IAdditionalProcessor.cs index c1e79f8..80073a5 100644 --- a/src/DotNetCore.CAP/Job/IAdditionalProcessor.cs +++ b/src/DotNetCore.CAP/Processor/IAdditionalProcessor.cs @@ -2,9 +2,10 @@ using System.Collections.Generic; using System.Text; -namespace DotNetCore.CAP.Job +namespace DotNetCore.CAP.Processor { public interface IAdditionalProcessor : IJobProcessor { + } } diff --git a/src/DotNetCore.CAP/Job/IJobProcessor.InfiniteRetry.cs b/src/DotNetCore.CAP/Processor/IJobProcessor.InfiniteRetry.cs similarity index 73% rename from src/DotNetCore.CAP/Job/IJobProcessor.InfiniteRetry.cs rename to src/DotNetCore.CAP/Processor/IJobProcessor.InfiniteRetry.cs index 619fa0a..8787771 100644 --- a/src/DotNetCore.CAP/Job/IJobProcessor.InfiniteRetry.cs +++ b/src/DotNetCore.CAP/Processor/IJobProcessor.InfiniteRetry.cs @@ -1,9 +1,8 @@ using System; -using System.Diagnostics; using System.Threading.Tasks; using Microsoft.Extensions.Logging; -namespace DotNetCore.CAP.Job +namespace DotNetCore.CAP.Processor { public class InfiniteRetryProcessor : IJobProcessor { @@ -24,7 +23,6 @@ namespace DotNetCore.CAP.Job { while (!context.IsStopping) { - Debug.WriteLine("InfiniteRetryProcessor在开线程:" + _inner.ToString() + " : " + DateTime.Now); try { await _inner.ProcessAsync(context); @@ -35,10 +33,7 @@ namespace DotNetCore.CAP.Job } catch (Exception ex) { - _logger.LogWarning( - 1, - ex, - "Prcessor '{ProcessorName}' failed. Retrying...", _inner.ToString()); + _logger.LogWarning(1, ex, "Prcessor '{ProcessorName}' failed. Retrying...", _inner.ToString()); } } } diff --git a/src/DotNetCore.CAP/Job/IJobProcessor.MessageJob.Default.cs b/src/DotNetCore.CAP/Processor/IJobProcessor.MessageJob.Default.cs similarity index 98% rename from src/DotNetCore.CAP/Job/IJobProcessor.MessageJob.Default.cs rename to src/DotNetCore.CAP/Processor/IJobProcessor.MessageJob.Default.cs index e880c36..a2b89ec 100644 --- a/src/DotNetCore.CAP/Job/IJobProcessor.MessageJob.Default.cs +++ b/src/DotNetCore.CAP/Processor/IJobProcessor.MessageJob.Default.cs @@ -6,7 +6,7 @@ using Microsoft.Extensions.DependencyInjection; using Microsoft.Extensions.Logging; using Microsoft.Extensions.Options; -namespace DotNetCore.CAP.Job +namespace DotNetCore.CAP.Processor { public class DefaultMessageJobProcessor : IMessageJobProcessor { diff --git a/src/DotNetCore.CAP/Job/IJobProcessor.JobQueuer.cs b/src/DotNetCore.CAP/Processor/IJobProcessor.PublishQueuer.cs similarity index 79% rename from src/DotNetCore.CAP/Job/IJobProcessor.JobQueuer.cs rename to src/DotNetCore.CAP/Processor/IJobProcessor.PublishQueuer.cs index 8973c17..0425431 100644 --- a/src/DotNetCore.CAP/Job/IJobProcessor.JobQueuer.cs +++ b/src/DotNetCore.CAP/Processor/IJobProcessor.PublishQueuer.cs @@ -2,15 +2,15 @@ using System.Threading; using System.Threading.Tasks; using DotNetCore.CAP.Infrastructure; -using DotNetCore.CAP.Job.States; +using DotNetCore.CAP.Processor.States; using DotNetCore.CAP.Models; using Microsoft.Extensions.DependencyInjection; using Microsoft.Extensions.Logging; using Microsoft.Extensions.Options; -namespace DotNetCore.CAP.Job +namespace DotNetCore.CAP.Processor { - public class JobQueuer : IJobProcessor + public class PublishQueuer : IJobProcessor { private ILogger _logger; private CapOptions _options; @@ -18,8 +18,10 @@ namespace DotNetCore.CAP.Job private IServiceProvider _provider; private TimeSpan _pollingDelay; - public JobQueuer( - ILogger logger, + internal static readonly AutoResetEvent PulseEvent = new AutoResetEvent(true); + + public PublishQueuer( + ILogger logger, IOptions options, IStateChanger stateChanger, IServiceProvider provider) @@ -57,8 +59,9 @@ namespace DotNetCore.CAP.Job context.ThrowIfStopping(); - WaitHandleEx.SentPulseEvent.Set(); - await WaitHandleEx.WaitAnyAsync(WaitHandleEx.QueuePulseEvent, + DefaultMessageJobProcessor.PulseEvent.Set(); + + await WaitHandleEx.WaitAnyAsync(PulseEvent, context.CancellationToken.WaitHandle, _pollingDelay); } } diff --git a/src/DotNetCore.CAP/Processor/IJobProcessor.SubscribeQueuer.cs b/src/DotNetCore.CAP/Processor/IJobProcessor.SubscribeQueuer.cs new file mode 100644 index 0000000..7e63d1a --- /dev/null +++ b/src/DotNetCore.CAP/Processor/IJobProcessor.SubscribeQueuer.cs @@ -0,0 +1,68 @@ +using System; +using System.Threading; +using System.Threading.Tasks; +using DotNetCore.CAP.Infrastructure; +using DotNetCore.CAP.Processor.States; +using DotNetCore.CAP.Models; +using Microsoft.Extensions.DependencyInjection; +using Microsoft.Extensions.Logging; +using Microsoft.Extensions.Options; + +namespace DotNetCore.CAP.Processor +{ + public class SubscribeQueuer : IJobProcessor + { + private ILogger _logger; + private CapOptions _options; + private IStateChanger _stateChanger; + private IServiceProvider _provider; + private TimeSpan _pollingDelay; + + internal static readonly AutoResetEvent PulseEvent = new AutoResetEvent(true); + + public SubscribeQueuer( + ILogger logger, + IOptions options, + IStateChanger stateChanger, + IServiceProvider provider) + { + _logger = logger; + _options = options.Value; + _stateChanger = stateChanger; + _provider = provider; + + _pollingDelay = TimeSpan.FromSeconds(_options.PollingDelay); + } + + public async Task ProcessAsync(ProcessingContext context) + { + using (var scope = _provider.CreateScope()) + { + CapReceivedMessage message; + var provider = scope.ServiceProvider; + var connection = provider.GetRequiredService(); + + while ( + !context.IsStopping && + (message = await connection.GetNextReceviedMessageToBeEnqueuedAsync()) != null) + + { + var state = new EnqueuedState(); + + using (var transaction = connection.CreateTransaction()) + { + _stateChanger.ChangeState(message, state, transaction); + await transaction.CommitAsync(); + } + } + } + + context.ThrowIfStopping(); + + DefaultMessageJobProcessor.PulseEvent.Set(); + + await WaitHandleEx.WaitAnyAsync(PulseEvent, + context.CancellationToken.WaitHandle, _pollingDelay); + } + } +} diff --git a/src/DotNetCore.CAP/Job/IJobProcessor.cs b/src/DotNetCore.CAP/Processor/IJobProcessor.cs similarity index 79% rename from src/DotNetCore.CAP/Job/IJobProcessor.cs rename to src/DotNetCore.CAP/Processor/IJobProcessor.cs index d7ffc76..4b9c15c 100644 --- a/src/DotNetCore.CAP/Job/IJobProcessor.cs +++ b/src/DotNetCore.CAP/Processor/IJobProcessor.cs @@ -1,6 +1,6 @@ using System.Threading.Tasks; -namespace DotNetCore.CAP.Job +namespace DotNetCore.CAP.Processor { public interface IJobProcessor { diff --git a/src/DotNetCore.CAP/Job/IMessageJobProcessor.cs b/src/DotNetCore.CAP/Processor/IMessageJobProcessor.cs similarity index 83% rename from src/DotNetCore.CAP/Job/IMessageJobProcessor.cs rename to src/DotNetCore.CAP/Processor/IMessageJobProcessor.cs index a280c0a..2f60494 100644 --- a/src/DotNetCore.CAP/Job/IMessageJobProcessor.cs +++ b/src/DotNetCore.CAP/Processor/IMessageJobProcessor.cs @@ -2,7 +2,7 @@ using System.Collections.Generic; using System.Text; -namespace DotNetCore.CAP.Job +namespace DotNetCore.CAP.Processor { public interface IMessageJobProcessor : IJobProcessor { diff --git a/src/DotNetCore.CAP/Job/IProcessingServer.Job.cs b/src/DotNetCore.CAP/Processor/IProcessingServer.Cap.cs similarity index 78% rename from src/DotNetCore.CAP/Job/IProcessingServer.Job.cs rename to src/DotNetCore.CAP/Processor/IProcessingServer.Cap.cs index 4724f53..87d12e7 100644 --- a/src/DotNetCore.CAP/Job/IProcessingServer.Job.cs +++ b/src/DotNetCore.CAP/Processor/IProcessingServer.Cap.cs @@ -3,14 +3,13 @@ using System.Collections.Generic; using System.Linq; using System.Threading; using System.Threading.Tasks; -using DotNetCore.CAP.Infrastructure; using Microsoft.Extensions.DependencyInjection; using Microsoft.Extensions.Logging; using Microsoft.Extensions.Options; -namespace DotNetCore.CAP.Job +namespace DotNetCore.CAP.Processor { - public class JobProcessingServer : IProcessingServer, IDisposable + public class CapProcessingServer : IProcessingServer, IDisposable { private readonly ILogger _logger; private readonly ILoggerFactory _loggerFactory; @@ -19,13 +18,13 @@ namespace DotNetCore.CAP.Job private readonly CapOptions _options; private IJobProcessor[] _processors; - private IMessageJobProcessor[] _messageProcessors; + private IList _messageProcessors; private ProcessingContext _context; private Task _compositeTask; private bool _disposed; - public JobProcessingServer( - ILogger logger, + public CapProcessingServer( + ILogger logger, ILoggerFactory loggerFactory, IServiceProvider provider, IOptions options) @@ -40,9 +39,8 @@ namespace DotNetCore.CAP.Job public void Start() { var processorCount = Environment.ProcessorCount; - processorCount = 1; _processors = GetProcessors(processorCount); - _logger.ServerStarting(processorCount, processorCount); + _logger.ServerStarting(processorCount, _processors.Length); _context = new ProcessingContext(_provider, _cts.Token); @@ -62,19 +60,8 @@ namespace DotNetCore.CAP.Job _logger.LogTrace("Pulsing the JobQueuer."); - WaitHandleEx.QueuePulseEvent.Set(); - } - - private bool AllProcessorsWaiting() - { - foreach (var processor in _messageProcessors) - { - if (!processor.Waiting) - { - return false; - } - } - return true; + PublishQueuer.PulseEvent.Set(); + SubscribeQueuer.PulseEvent.Set(); } public void Dispose() @@ -101,6 +88,18 @@ namespace DotNetCore.CAP.Job } } + private bool AllProcessorsWaiting() + { + foreach (var processor in _messageProcessors) + { + if (!processor.Waiting) + { + return false; + } + } + return true; + } + private IJobProcessor InfiniteRetry(IJobProcessor inner) { return new InfiniteRetryProcessor(inner, _loggerFactory); @@ -111,13 +110,15 @@ namespace DotNetCore.CAP.Job var returnedProcessors = new List(); for (int i = 0; i < processorCount; i++) { - var messageProcessors = _provider.GetServices(); - _messageProcessors = messageProcessors.ToArray(); - returnedProcessors.AddRange(messageProcessors); + var messageProcessors = _provider.GetService(); + _messageProcessors.Add(messageProcessors); } + returnedProcessors.AddRange(_messageProcessors); + + returnedProcessors.Add(_provider.GetService()); + returnedProcessors.Add(_provider.GetService()); - returnedProcessors.Add(_provider.GetService()); - //returnedProcessors.Add(_provider.GetService()); + returnedProcessors.Add(_provider.GetService()); return returnedProcessors.ToArray(); } diff --git a/src/DotNetCore.CAP/Job/ProcessingContext.cs b/src/DotNetCore.CAP/Processor/ProcessingContext.cs similarity index 97% rename from src/DotNetCore.CAP/Job/ProcessingContext.cs rename to src/DotNetCore.CAP/Processor/ProcessingContext.cs index 764ae80..f1fb203 100644 --- a/src/DotNetCore.CAP/Job/ProcessingContext.cs +++ b/src/DotNetCore.CAP/Processor/ProcessingContext.cs @@ -3,7 +3,7 @@ using System.Threading; using System.Threading.Tasks; using Microsoft.Extensions.DependencyInjection; -namespace DotNetCore.CAP.Job +namespace DotNetCore.CAP.Processor { public class ProcessingContext : IDisposable { diff --git a/src/DotNetCore.CAP/Job/RetryBehavior.cs b/src/DotNetCore.CAP/Processor/RetryBehavior.cs similarity index 98% rename from src/DotNetCore.CAP/Job/RetryBehavior.cs rename to src/DotNetCore.CAP/Processor/RetryBehavior.cs index 9d48d59..04cb667 100644 --- a/src/DotNetCore.CAP/Job/RetryBehavior.cs +++ b/src/DotNetCore.CAP/Processor/RetryBehavior.cs @@ -1,6 +1,6 @@ using System; -namespace DotNetCore.CAP.Job +namespace DotNetCore.CAP.Processor { public class RetryBehavior { diff --git a/src/DotNetCore.CAP/Job/States/IState.Enqueued.cs b/src/DotNetCore.CAP/Processor/States/IState.Enqueued.cs similarity index 92% rename from src/DotNetCore.CAP/Job/States/IState.Enqueued.cs rename to src/DotNetCore.CAP/Processor/States/IState.Enqueued.cs index 6588177..41d83ae 100644 --- a/src/DotNetCore.CAP/Job/States/IState.Enqueued.cs +++ b/src/DotNetCore.CAP/Processor/States/IState.Enqueued.cs @@ -1,7 +1,7 @@ using System; using DotNetCore.CAP.Models; -namespace DotNetCore.CAP.Job.States +namespace DotNetCore.CAP.Processor.States { public class EnqueuedState : IState { diff --git a/src/DotNetCore.CAP/Job/States/IState.Failed.cs b/src/DotNetCore.CAP/Processor/States/IState.Failed.cs similarity index 91% rename from src/DotNetCore.CAP/Job/States/IState.Failed.cs rename to src/DotNetCore.CAP/Processor/States/IState.Failed.cs index c779856..9bbfbd6 100644 --- a/src/DotNetCore.CAP/Job/States/IState.Failed.cs +++ b/src/DotNetCore.CAP/Processor/States/IState.Failed.cs @@ -1,7 +1,7 @@ using System; using DotNetCore.CAP.Models; -namespace DotNetCore.CAP.Job.States +namespace DotNetCore.CAP.Processor.States { public class FailedState : IState { diff --git a/src/DotNetCore.CAP/Job/States/IState.Processing.cs b/src/DotNetCore.CAP/Processor/States/IState.Processing.cs similarity index 91% rename from src/DotNetCore.CAP/Job/States/IState.Processing.cs rename to src/DotNetCore.CAP/Processor/States/IState.Processing.cs index a5564a8..db66b86 100644 --- a/src/DotNetCore.CAP/Job/States/IState.Processing.cs +++ b/src/DotNetCore.CAP/Processor/States/IState.Processing.cs @@ -1,7 +1,7 @@ using System; using DotNetCore.CAP.Models; -namespace DotNetCore.CAP.Job.States +namespace DotNetCore.CAP.Processor.States { public class ProcessingState : IState { diff --git a/src/DotNetCore.CAP/Job/States/IState.Scheduled.cs b/src/DotNetCore.CAP/Processor/States/IState.Scheduled.cs similarity index 91% rename from src/DotNetCore.CAP/Job/States/IState.Scheduled.cs rename to src/DotNetCore.CAP/Processor/States/IState.Scheduled.cs index 6a38697..6113f3b 100644 --- a/src/DotNetCore.CAP/Job/States/IState.Scheduled.cs +++ b/src/DotNetCore.CAP/Processor/States/IState.Scheduled.cs @@ -1,7 +1,7 @@ using System; using DotNetCore.CAP.Models; -namespace DotNetCore.CAP.Job.States +namespace DotNetCore.CAP.Processor.States { public class ScheduledState : IState { diff --git a/src/DotNetCore.CAP/Job/States/IState.Succeeded.cs b/src/DotNetCore.CAP/Processor/States/IState.Succeeded.cs similarity index 91% rename from src/DotNetCore.CAP/Job/States/IState.Succeeded.cs rename to src/DotNetCore.CAP/Processor/States/IState.Succeeded.cs index 384de56..b3b4f4d 100644 --- a/src/DotNetCore.CAP/Job/States/IState.Succeeded.cs +++ b/src/DotNetCore.CAP/Processor/States/IState.Succeeded.cs @@ -1,7 +1,7 @@ using System; using DotNetCore.CAP.Models; -namespace DotNetCore.CAP.Job.States +namespace DotNetCore.CAP.Processor.States { public class SucceededState : IState { diff --git a/src/DotNetCore.CAP/Job/States/IState.cs b/src/DotNetCore.CAP/Processor/States/IState.cs similarity index 88% rename from src/DotNetCore.CAP/Job/States/IState.cs rename to src/DotNetCore.CAP/Processor/States/IState.cs index 2219dcb..0416fe9 100644 --- a/src/DotNetCore.CAP/Job/States/IState.cs +++ b/src/DotNetCore.CAP/Processor/States/IState.cs @@ -1,7 +1,7 @@ using System; using DotNetCore.CAP.Models; -namespace DotNetCore.CAP.Job.States +namespace DotNetCore.CAP.Processor.States { public interface IState { diff --git a/src/DotNetCore.CAP/Job/States/IStateChanger.Default.cs b/src/DotNetCore.CAP/Processor/States/IStateChanger.Default.cs similarity index 96% rename from src/DotNetCore.CAP/Job/States/IStateChanger.Default.cs rename to src/DotNetCore.CAP/Processor/States/IStateChanger.Default.cs index b3f2d2a..1e4c99b 100644 --- a/src/DotNetCore.CAP/Job/States/IStateChanger.Default.cs +++ b/src/DotNetCore.CAP/Processor/States/IStateChanger.Default.cs @@ -1,6 +1,6 @@ using DotNetCore.CAP.Models; -namespace DotNetCore.CAP.Job.States +namespace DotNetCore.CAP.Processor.States { public class StateChanger : IStateChanger { diff --git a/src/DotNetCore.CAP/Job/States/IStateChanger.Extensions.cs b/src/DotNetCore.CAP/Processor/States/IStateChanger.Extensions.cs similarity index 95% rename from src/DotNetCore.CAP/Job/States/IStateChanger.Extensions.cs rename to src/DotNetCore.CAP/Processor/States/IStateChanger.Extensions.cs index 27ec4e9..5ccc018 100644 --- a/src/DotNetCore.CAP/Job/States/IStateChanger.Extensions.cs +++ b/src/DotNetCore.CAP/Processor/States/IStateChanger.Extensions.cs @@ -1,7 +1,7 @@ using System.Threading.Tasks; using DotNetCore.CAP.Models; -namespace DotNetCore.CAP.Job.States +namespace DotNetCore.CAP.Processor.States { public static class StateChangerExtensions { diff --git a/src/DotNetCore.CAP/Job/States/IStateChanger.cs b/src/DotNetCore.CAP/Processor/States/IStateChanger.cs similarity index 86% rename from src/DotNetCore.CAP/Job/States/IStateChanger.cs rename to src/DotNetCore.CAP/Processor/States/IStateChanger.cs index 662e4e1..1cba968 100644 --- a/src/DotNetCore.CAP/Job/States/IStateChanger.cs +++ b/src/DotNetCore.CAP/Processor/States/IStateChanger.cs @@ -1,6 +1,6 @@ using DotNetCore.CAP.Models; -namespace DotNetCore.CAP.Job.States +namespace DotNetCore.CAP.Processor.States { public interface IStateChanger { From 64dcc7fc53d67400f0d724dfc53904a1e446a5e4 Mon Sep 17 00:00:00 2001 From: Savorboard Date: Fri, 14 Jul 2017 01:09:14 +0800 Subject: [PATCH 10/68] rename --- .../IProcessor.KafkaJobProcessor.cs | 122 ----------- ...IMessageJobProcessor.RabbitJobProcessor.cs | 206 ------------------ .../Processor/IAdditionalProcessor.cs | 2 +- ...geJobProcessor.cs => IMessageProcessor.cs} | 2 +- .../Processor/IProcessingServer.Cap.cs | 12 +- ...teRetry.cs => IProcessor.InfiniteRetry.cs} | 6 +- ...fault.cs => IProcessor.Message.Default.cs} | 6 +- ...hQueuer.cs => IProcessor.PublishQueuer.cs} | 6 +- ...ueuer.cs => IProcessor.SubscribeQueuer.cs} | 4 +- .../{IJobProcessor.cs => IProcessor.cs} | 2 +- 10 files changed, 20 insertions(+), 348 deletions(-) delete mode 100644 src/DotNetCore.CAP.Kafka/IProcessor.KafkaJobProcessor.cs delete mode 100644 src/DotNetCore.CAP.RabbitMQ/IMessageJobProcessor.RabbitJobProcessor.cs rename src/DotNetCore.CAP/Processor/{IMessageJobProcessor.cs => IMessageProcessor.cs} (72%) rename src/DotNetCore.CAP/Processor/{IJobProcessor.InfiniteRetry.cs => IProcessor.InfiniteRetry.cs} (88%) rename src/DotNetCore.CAP/Processor/{IJobProcessor.MessageJob.Default.cs => IProcessor.Message.Default.cs} (94%) rename src/DotNetCore.CAP/Processor/{IJobProcessor.PublishQueuer.cs => IProcessor.PublishQueuer.cs} (90%) rename src/DotNetCore.CAP/Processor/{IJobProcessor.SubscribeQueuer.cs => IProcessor.SubscribeQueuer.cs} (95%) rename src/DotNetCore.CAP/Processor/{IJobProcessor.cs => IProcessor.cs} (79%) diff --git a/src/DotNetCore.CAP.Kafka/IProcessor.KafkaJobProcessor.cs b/src/DotNetCore.CAP.Kafka/IProcessor.KafkaJobProcessor.cs deleted file mode 100644 index 678feda..0000000 --- a/src/DotNetCore.CAP.Kafka/IProcessor.KafkaJobProcessor.cs +++ /dev/null @@ -1,122 +0,0 @@ -using System; -using System.Collections.Generic; -using System.Diagnostics; -using System.Text; -using System.Threading; -using System.Threading.Tasks; -using Confluent.Kafka; -using Confluent.Kafka.Serialization; -using DotNetCore.CAP.Infrastructure; -using DotNetCore.CAP.Job; -using Microsoft.Extensions.DependencyInjection; -using Microsoft.Extensions.Logging; -using Microsoft.Extensions.Options; - -namespace DotNetCore.CAP.Kafka -{ - public class KafkaJobProcessor : IJobProcessor - { - private readonly KafkaOptions _kafkaOptions; - private readonly CancellationTokenSource _cts; - - private readonly IServiceProvider _provider; - private readonly ILogger _logger; - - private readonly TimeSpan _pollingDelay; - - public KafkaJobProcessor( - IOptions capOptions, - IOptions kafkaOptions, - ILogger logger, - IServiceProvider provider) - { - _logger = logger; - _kafkaOptions = kafkaOptions.Value; - _provider = provider; - _cts = new CancellationTokenSource(); - _pollingDelay = TimeSpan.FromSeconds(capOptions.Value.PollingDelay); - } - - public bool Waiting { get; private set; } - - public Task ProcessAsync(ProcessingContext context) - { - if (context == null) throw new ArgumentNullException(nameof(context)); - - context.ThrowIfStopping(); - return ProcessCoreAsync(context); - } - - public async Task ProcessCoreAsync(ProcessingContext context) - { - try - { - var worked = await Step(context); - - context.ThrowIfStopping(); - - Waiting = true; - - if (!worked) - { - var token = GetTokenToWaitOn(context); - } - - await WaitHandleEx.WaitAnyAsync(WaitHandleEx.PulseEvent, - context.CancellationToken.WaitHandle, _pollingDelay); - } - finally - { - Waiting = false; - } - } - - protected virtual CancellationToken GetTokenToWaitOn(ProcessingContext context) - { - return context.CancellationToken; - } - - private async Task Step(ProcessingContext context) - { - throw new NotImplementedException(); - // using (var scopedContext = context.CreateScope()) - // { - // var provider = scopedContext.Provider; - // var messageStore = provider.GetRequiredService(); - // var message = await messageStore.GetNextSentMessageToBeEnqueuedAsync(); - // if (message == null) return true; - // try - // { - // var sp = Stopwatch.StartNew(); - // message.StatusName = StatusName.Processing; - // await messageStore.UpdateSentMessageAsync(message); - - // await ExecuteJobAsync(message.KeyName, message.Content); - - // sp.Stop(); - - // message.StatusName = StatusName.Succeeded; - // await messageStore.UpdateSentMessageAsync(message); - // _logger.JobExecuted(sp.Elapsed.TotalSeconds); - // } - // catch (Exception ex) - // { - // _logger.ExceptionOccuredWhileExecutingJob(message.KeyName, ex); - // return false; - // } - // } - // return true; - } - - private Task ExecuteJobAsync(string topic, string content) - { - var config = _kafkaOptions.AsRdkafkaConfig(); - using (var producer = new Producer(config, null, new StringSerializer(Encoding.UTF8))) - { - producer.ProduceAsync(topic, null, content); - producer.Flush(); - } - return Task.CompletedTask; - } - } -} \ No newline at end of file diff --git a/src/DotNetCore.CAP.RabbitMQ/IMessageJobProcessor.RabbitJobProcessor.cs b/src/DotNetCore.CAP.RabbitMQ/IMessageJobProcessor.RabbitJobProcessor.cs deleted file mode 100644 index 5a8ff3b..0000000 --- a/src/DotNetCore.CAP.RabbitMQ/IMessageJobProcessor.RabbitJobProcessor.cs +++ /dev/null @@ -1,206 +0,0 @@ -using System; -using System.Diagnostics; -using System.Text; -using System.Threading; -using System.Threading.Tasks; -using DotNetCore.CAP.Infrastructure; -using DotNetCore.CAP.Job; -using DotNetCore.CAP.Job.States; -using DotNetCore.CAP.Models; -using Microsoft.Extensions.DependencyInjection; -using Microsoft.Extensions.Logging; -using Microsoft.Extensions.Options; -using RabbitMQ.Client; - -namespace DotNetCore.CAP.RabbitMQ -{ - public class RabbitJobProcessor : IMessageJobProcessor - { - private readonly RabbitMQOptions _rabbitMqOptions; - private readonly CancellationTokenSource _cts; - private readonly IStateChanger _stateChanger; - private readonly IServiceProvider _provider; - private readonly ILogger _logger; - - private readonly TimeSpan _pollingDelay; - - public RabbitJobProcessor( - IOptions capOptions, - IOptions rabbitMQOptions, - ILogger logger, - IStateChanger stateChanger, - IServiceProvider provider) - { - _logger = logger; - _rabbitMqOptions = rabbitMQOptions.Value; - _provider = provider; - _stateChanger = stateChanger; - _cts = new CancellationTokenSource(); - - var capOptions1 = capOptions.Value; - _pollingDelay = TimeSpan.FromSeconds(capOptions1.PollingDelay); - } - - public bool Waiting { get; private set; } - - public Task ProcessAsync(ProcessingContext context) - { - if (context == null) throw new ArgumentNullException(nameof(context)); - System.Diagnostics.Debug.WriteLine("RabbitMQ Processor 执行: " + DateTime.Now); - context.ThrowIfStopping(); - return ProcessCoreAsync(context); - } - - public async Task ProcessCoreAsync(ProcessingContext context) - { - try - { - var worked = await Step(context); - - context.ThrowIfStopping(); - - Waiting = true; - - if (!worked) - { - var token = GetTokenToWaitOn(context); - - await WaitHandleEx.WaitAnyAsync(WaitHandleEx.SentPulseEvent, token.WaitHandle, _pollingDelay); - } - } - finally - { - Waiting = false; - } - } - - protected virtual CancellationToken GetTokenToWaitOn(ProcessingContext context) - { - return context.CancellationToken; - } - - private async Task Step(ProcessingContext context) - { - var fetched = default(IFetchedMessage); - using (var scopedContext = context.CreateScope()) - { - var provider = scopedContext.Provider; - var connection = provider.GetRequiredService(); - - if ((fetched = await connection.FetchNextMessageAsync()) != null) - { - using (fetched) - { - - var message = await connection.GetSentMessageAsync(fetched.MessageId); - try - { - var sp = Stopwatch.StartNew(); - await _stateChanger.ChangeStateAsync(message, new ProcessingState(), connection); - - if (message.Retries > 0) - { - _logger.JobRetrying(message.Retries); - } - var result = ExecuteJob(message.KeyName, message.Content); - sp.Stop(); - - var newState = default(IState); - if (!result.Succeeded) - { - var shouldRetry = await UpdateJobForRetryAsync(message, connection); - if (shouldRetry) - { - newState = new ScheduledState(); - _logger.JobFailedWillRetry(result.Exception); - } - else - { - newState = new FailedState(); - _logger.JobFailed(result.Exception); - } - } - else - { - newState = new SucceededState(); - } - await _stateChanger.ChangeStateAsync(message, newState, connection); - - fetched.RemoveFromQueue(); - - if (result.Succeeded) - { - _logger.JobExecuted(sp.Elapsed.TotalSeconds); - } - } - - catch (Exception ex) - { - _logger.ExceptionOccuredWhileExecutingJob(message?.KeyName, ex); - return false; - } - - } - } - } - return fetched != null; - } - - private async Task UpdateJobForRetryAsync(CapSentMessage message, IStorageConnection connection) - { - var retryBehavior = RetryBehavior.DefaultRetry; - - var now = DateTime.UtcNow; - var retries = ++message.Retries; - if (retries >= retryBehavior.RetryCount) - { - return false; - } - - var due = message.Added.AddSeconds(retryBehavior.RetryIn(retries)); - message.LastRun = due; - using (var transaction = connection.CreateTransaction()) - { - transaction.UpdateMessage(message); - await transaction.CommitAsync(); - } - return true; - } - - private OperateResult ExecuteJob(string topic, string content) - { - var factory = new ConnectionFactory() - { - HostName = _rabbitMqOptions.HostName, - UserName = _rabbitMqOptions.UserName, - Port = _rabbitMqOptions.Port, - Password = _rabbitMqOptions.Password, - VirtualHost = _rabbitMqOptions.VirtualHost, - RequestedConnectionTimeout = _rabbitMqOptions.RequestedConnectionTimeout, - SocketReadTimeout = _rabbitMqOptions.SocketReadTimeout, - SocketWriteTimeout = _rabbitMqOptions.SocketWriteTimeout - }; - - try - { - using (var connection = factory.CreateConnection()) - using (var channel = connection.CreateModel()) - { - var body = Encoding.UTF8.GetBytes(content); - - channel.ExchangeDeclare(_rabbitMqOptions.TopicExchangeName, _rabbitMqOptions.EXCHANGE_TYPE); - channel.BasicPublish(exchange: _rabbitMqOptions.TopicExchangeName, - routingKey: topic, - basicProperties: null, - body: body); - } - return OperateResult.Success; - } - catch (Exception ex) - { - return OperateResult.Failed(ex, new OperateError() { Code = ex.HResult.ToString(), Description = ex.Message }); - } - - } - } -} \ No newline at end of file diff --git a/src/DotNetCore.CAP/Processor/IAdditionalProcessor.cs b/src/DotNetCore.CAP/Processor/IAdditionalProcessor.cs index 80073a5..9c414ff 100644 --- a/src/DotNetCore.CAP/Processor/IAdditionalProcessor.cs +++ b/src/DotNetCore.CAP/Processor/IAdditionalProcessor.cs @@ -4,7 +4,7 @@ using System.Text; namespace DotNetCore.CAP.Processor { - public interface IAdditionalProcessor : IJobProcessor + public interface IAdditionalProcessor : IProcessor { } diff --git a/src/DotNetCore.CAP/Processor/IMessageJobProcessor.cs b/src/DotNetCore.CAP/Processor/IMessageProcessor.cs similarity index 72% rename from src/DotNetCore.CAP/Processor/IMessageJobProcessor.cs rename to src/DotNetCore.CAP/Processor/IMessageProcessor.cs index 2f60494..e26b6fa 100644 --- a/src/DotNetCore.CAP/Processor/IMessageJobProcessor.cs +++ b/src/DotNetCore.CAP/Processor/IMessageProcessor.cs @@ -4,7 +4,7 @@ using System.Text; namespace DotNetCore.CAP.Processor { - public interface IMessageJobProcessor : IJobProcessor + public interface IMessageProcessor : IProcessor { bool Waiting { get; } } diff --git a/src/DotNetCore.CAP/Processor/IProcessingServer.Cap.cs b/src/DotNetCore.CAP/Processor/IProcessingServer.Cap.cs index 87d12e7..d5bc699 100644 --- a/src/DotNetCore.CAP/Processor/IProcessingServer.Cap.cs +++ b/src/DotNetCore.CAP/Processor/IProcessingServer.Cap.cs @@ -17,8 +17,8 @@ namespace DotNetCore.CAP.Processor private readonly CancellationTokenSource _cts; private readonly CapOptions _options; - private IJobProcessor[] _processors; - private IList _messageProcessors; + private IProcessor[] _processors; + private IList _messageProcessors; private ProcessingContext _context; private Task _compositeTask; private bool _disposed; @@ -100,17 +100,17 @@ namespace DotNetCore.CAP.Processor return true; } - private IJobProcessor InfiniteRetry(IJobProcessor inner) + private IProcessor InfiniteRetry(IProcessor inner) { return new InfiniteRetryProcessor(inner, _loggerFactory); } - private IJobProcessor[] GetProcessors(int processorCount) + private IProcessor[] GetProcessors(int processorCount) { - var returnedProcessors = new List(); + var returnedProcessors = new List(); for (int i = 0; i < processorCount; i++) { - var messageProcessors = _provider.GetService(); + var messageProcessors = _provider.GetService(); _messageProcessors.Add(messageProcessors); } returnedProcessors.AddRange(_messageProcessors); diff --git a/src/DotNetCore.CAP/Processor/IJobProcessor.InfiniteRetry.cs b/src/DotNetCore.CAP/Processor/IProcessor.InfiniteRetry.cs similarity index 88% rename from src/DotNetCore.CAP/Processor/IJobProcessor.InfiniteRetry.cs rename to src/DotNetCore.CAP/Processor/IProcessor.InfiniteRetry.cs index 8787771..2c28d03 100644 --- a/src/DotNetCore.CAP/Processor/IJobProcessor.InfiniteRetry.cs +++ b/src/DotNetCore.CAP/Processor/IProcessor.InfiniteRetry.cs @@ -4,13 +4,13 @@ using Microsoft.Extensions.Logging; namespace DotNetCore.CAP.Processor { - public class InfiniteRetryProcessor : IJobProcessor + public class InfiniteRetryProcessor : IProcessor { - private readonly IJobProcessor _inner; + private readonly IProcessor _inner; private readonly ILogger _logger; public InfiniteRetryProcessor( - IJobProcessor inner, + IProcessor inner, ILoggerFactory loggerFactory) { _inner = inner; diff --git a/src/DotNetCore.CAP/Processor/IJobProcessor.MessageJob.Default.cs b/src/DotNetCore.CAP/Processor/IProcessor.Message.Default.cs similarity index 94% rename from src/DotNetCore.CAP/Processor/IJobProcessor.MessageJob.Default.cs rename to src/DotNetCore.CAP/Processor/IProcessor.Message.Default.cs index a2b89ec..a9f6542 100644 --- a/src/DotNetCore.CAP/Processor/IJobProcessor.MessageJob.Default.cs +++ b/src/DotNetCore.CAP/Processor/IProcessor.Message.Default.cs @@ -8,7 +8,7 @@ using Microsoft.Extensions.Options; namespace DotNetCore.CAP.Processor { - public class DefaultMessageJobProcessor : IMessageJobProcessor + public class DefaultMessageProcessor : IMessageProcessor { private readonly IQueueExecutorFactory _queueExecutorFactory; private readonly IServiceProvider _provider; @@ -19,11 +19,11 @@ namespace DotNetCore.CAP.Processor internal static readonly AutoResetEvent PulseEvent = new AutoResetEvent(true); - public DefaultMessageJobProcessor( + public DefaultMessageProcessor( IServiceProvider provider, IQueueExecutorFactory queueExecutorFactory, IOptions capOptions, - ILogger logger) + ILogger logger) { _logger = logger; _queueExecutorFactory = queueExecutorFactory; diff --git a/src/DotNetCore.CAP/Processor/IJobProcessor.PublishQueuer.cs b/src/DotNetCore.CAP/Processor/IProcessor.PublishQueuer.cs similarity index 90% rename from src/DotNetCore.CAP/Processor/IJobProcessor.PublishQueuer.cs rename to src/DotNetCore.CAP/Processor/IProcessor.PublishQueuer.cs index 0425431..cc9f644 100644 --- a/src/DotNetCore.CAP/Processor/IJobProcessor.PublishQueuer.cs +++ b/src/DotNetCore.CAP/Processor/IProcessor.PublishQueuer.cs @@ -10,7 +10,7 @@ using Microsoft.Extensions.Options; namespace DotNetCore.CAP.Processor { - public class PublishQueuer : IJobProcessor + public class PublishQueuer : IProcessor { private ILogger _logger; private CapOptions _options; @@ -18,7 +18,7 @@ namespace DotNetCore.CAP.Processor private IServiceProvider _provider; private TimeSpan _pollingDelay; - internal static readonly AutoResetEvent PulseEvent = new AutoResetEvent(true); + public static readonly AutoResetEvent PulseEvent = new AutoResetEvent(true); public PublishQueuer( ILogger logger, @@ -59,7 +59,7 @@ namespace DotNetCore.CAP.Processor context.ThrowIfStopping(); - DefaultMessageJobProcessor.PulseEvent.Set(); + DefaultMessageProcessor.PulseEvent.Set(); await WaitHandleEx.WaitAnyAsync(PulseEvent, context.CancellationToken.WaitHandle, _pollingDelay); diff --git a/src/DotNetCore.CAP/Processor/IJobProcessor.SubscribeQueuer.cs b/src/DotNetCore.CAP/Processor/IProcessor.SubscribeQueuer.cs similarity index 95% rename from src/DotNetCore.CAP/Processor/IJobProcessor.SubscribeQueuer.cs rename to src/DotNetCore.CAP/Processor/IProcessor.SubscribeQueuer.cs index 7e63d1a..7d1b7c2 100644 --- a/src/DotNetCore.CAP/Processor/IJobProcessor.SubscribeQueuer.cs +++ b/src/DotNetCore.CAP/Processor/IProcessor.SubscribeQueuer.cs @@ -10,7 +10,7 @@ using Microsoft.Extensions.Options; namespace DotNetCore.CAP.Processor { - public class SubscribeQueuer : IJobProcessor + public class SubscribeQueuer : IProcessor { private ILogger _logger; private CapOptions _options; @@ -59,7 +59,7 @@ namespace DotNetCore.CAP.Processor context.ThrowIfStopping(); - DefaultMessageJobProcessor.PulseEvent.Set(); + DefaultMessageProcessor.PulseEvent.Set(); await WaitHandleEx.WaitAnyAsync(PulseEvent, context.CancellationToken.WaitHandle, _pollingDelay); diff --git a/src/DotNetCore.CAP/Processor/IJobProcessor.cs b/src/DotNetCore.CAP/Processor/IProcessor.cs similarity index 79% rename from src/DotNetCore.CAP/Processor/IJobProcessor.cs rename to src/DotNetCore.CAP/Processor/IProcessor.cs index 4b9c15c..20d484f 100644 --- a/src/DotNetCore.CAP/Processor/IJobProcessor.cs +++ b/src/DotNetCore.CAP/Processor/IProcessor.cs @@ -2,7 +2,7 @@ namespace DotNetCore.CAP.Processor { - public interface IJobProcessor + public interface IProcessor { Task ProcessAsync(ProcessingContext context); } From ceee751e4a476e867c2228ff0a8caba337e7b782 Mon Sep 17 00:00:00 2001 From: Savorboard Date: Fri, 14 Jul 2017 01:09:44 +0800 Subject: [PATCH 11/68] refactor publisher and subscribe --- .../CAP.BuilderExtensions.cs | 20 ++---- .../CapPublisherExtensions.cs | 9 +-- .../EFStorageConnection.cs | 19 ++--- .../IAdditionalProcessor.Default.cs | 70 +++++++++++++++++++ .../CAP.BuilderExtensions.cs | 3 +- .../PublishQueueExecutor.cs | 54 ++++++++++++++ .../CAP.BuilderExtensions.cs | 3 +- .../PublishQueueExecutor.cs | 70 +++++++++++++++++++ src/DotNetCore.CAP/CAP.Builder.cs | 1 - .../CAP.ServiceCollectionExtensions.cs | 14 ++-- src/DotNetCore.CAP/DotNetCore.CAP.csproj | 2 +- src/DotNetCore.CAP/IBootstrapper.Default.cs | 1 - .../IConsumerHandler.Default.cs | 37 +--------- .../IQueueExecutor.Publish.Base.cs | 6 +- src/DotNetCore.CAP/IQueueExecutor.Subscibe.cs | 10 +-- .../Infrastructure/WaitHandleEx.cs | 5 -- src/DotNetCore.CAP/LoggerExtensions.cs | 2 +- .../Models/CapReceivedMessage.cs | 2 +- src/DotNetCore.CAP/Models/CapSentMessage.cs | 2 +- test/DotNetCore.CAP.Test/CAP.BuilderTest.cs | 2 +- .../Job/ComputedJobTest.cs | 2 +- .../Job/JobProcessingServerTest.cs | 2 +- 22 files changed, 239 insertions(+), 97 deletions(-) create mode 100644 src/DotNetCore.CAP.EntityFrameworkCore/IAdditionalProcessor.Default.cs create mode 100644 src/DotNetCore.CAP.Kafka/PublishQueueExecutor.cs create mode 100644 src/DotNetCore.CAP.RabbitMQ/PublishQueueExecutor.cs diff --git a/src/DotNetCore.CAP.EntityFrameworkCore/CAP.BuilderExtensions.cs b/src/DotNetCore.CAP.EntityFrameworkCore/CAP.BuilderExtensions.cs index 938cb50..668f090 100644 --- a/src/DotNetCore.CAP.EntityFrameworkCore/CAP.BuilderExtensions.cs +++ b/src/DotNetCore.CAP.EntityFrameworkCore/CAP.BuilderExtensions.cs @@ -1,6 +1,7 @@ using System; using DotNetCore.CAP; using DotNetCore.CAP.EntityFrameworkCore; +using DotNetCore.CAP.Processor; using Microsoft.EntityFrameworkCore; namespace Microsoft.Extensions.DependencyInjection @@ -13,26 +14,17 @@ namespace Microsoft.Extensions.DependencyInjection /// /// Adds an Entity Framework implementation of message stores. /// - /// The Entity Framework database context to use. - /// The instance this method extends. - public static CapBuilder AddEntityFrameworkStores(this CapBuilder builder) - where TContext : DbContext - { - //builder.Services.AddScoped>(); - builder.Services.AddScoped(); - builder.Services.AddScoped(); - - return builder; - } - - public static CapBuilder AddEntityFrameworkStores(this CapBuilder builder, Action actionOptions) where TContext : DbContext { //builder.Services.AddScoped>(); + builder.Services.AddSingleton(); - builder.Services.AddScoped(); + builder.Services.AddScoped(); + + builder.Services.AddTransient(); + builder.Services.Configure(actionOptions); var sqlServerOptions = new SqlServerOptions(); diff --git a/src/DotNetCore.CAP.EntityFrameworkCore/CapPublisherExtensions.cs b/src/DotNetCore.CAP.EntityFrameworkCore/CapPublisherExtensions.cs index 83faf1e..ad9d5be 100644 --- a/src/DotNetCore.CAP.EntityFrameworkCore/CapPublisherExtensions.cs +++ b/src/DotNetCore.CAP.EntityFrameworkCore/CapPublisherExtensions.cs @@ -7,6 +7,7 @@ using Dapper; using Microsoft.EntityFrameworkCore; using Microsoft.EntityFrameworkCore.Infrastructure; using DotNetCore.CAP.Infrastructure; +using DotNetCore.CAP.Processor; namespace DotNetCore.CAP { @@ -25,9 +26,9 @@ namespace DotNetCore.CAP StatusName = StatusName.Enqueued }; - var sql = "INSERT INTO [cap].[CapSentMessages] ([Id],[Added],[Content],[KeyName],[LastRun],[Retries],[StatusName])VALUES(@Id,@Added,@Content,@KeyName,@LastRun,@Retries,@StatusName)"; + var sql = "INSERT INTO [cap].[CapSentMessages] ([Id],[Added],[Content],[KeyName],[ExpiresAt],[Retries],[StatusName])VALUES(@Id,@Added,@Content,@KeyName,@ExpiresAt,@Retries,@StatusName)"; await connection.ExecuteAsync(sql, transaction); - WaitHandleEx.QueuePulseEvent.Set(); + PublishQueuer.PulseEvent.Set(); } @@ -40,9 +41,9 @@ namespace DotNetCore.CAP StatusName = StatusName.Enqueued }; - var sql = "INSERT INTO [cap].[CapSentMessages] ([Id],[Added],[Content],[KeyName],[LastRun],[Retries],[StatusName])VALUES(@Id,@Added,@Content,@KeyName,@LastRun,@Retries,@StatusName)"; + var sql = "INSERT INTO [cap].[CapSentMessages] ([Id],[Added],[Content],[KeyName],[ExpiresAt],[Retries],[StatusName])VALUES(@Id,@Added,@Content,@KeyName,@ExpiresAt,@Retries,@StatusName)"; await connection.ExecuteAsync(sql, transaction); - WaitHandleEx.QueuePulseEvent.Set(); + PublishQueuer.PulseEvent.Set(); } } } \ No newline at end of file diff --git a/src/DotNetCore.CAP.EntityFrameworkCore/EFStorageConnection.cs b/src/DotNetCore.CAP.EntityFrameworkCore/EFStorageConnection.cs index c9305c1..f996028 100644 --- a/src/DotNetCore.CAP.EntityFrameworkCore/EFStorageConnection.cs +++ b/src/DotNetCore.CAP.EntityFrameworkCore/EFStorageConnection.cs @@ -58,22 +58,15 @@ SELECT TOP (1) * FROM [{_options.Schema}].[{nameof(CapDbContext.CapSentMessages)}] WITH (readpast) WHERE StatusName = '{StatusName.Scheduled}'"; - try - { - var connection = _context.GetDbConnection(); - var message = (await connection.QueryAsync(sql)).FirstOrDefault(); - - if (message != null) - { - _context.Attach(message); - } + var connection = _context.GetDbConnection(); + var message = (await connection.QueryAsync(sql)).FirstOrDefault(); - return message; - } - catch (Exception ex) + if (message != null) { - throw; + _context.Attach(message); } + + return message; } // CapReceviedMessage diff --git a/src/DotNetCore.CAP.EntityFrameworkCore/IAdditionalProcessor.Default.cs b/src/DotNetCore.CAP.EntityFrameworkCore/IAdditionalProcessor.Default.cs new file mode 100644 index 0000000..4014e4d --- /dev/null +++ b/src/DotNetCore.CAP.EntityFrameworkCore/IAdditionalProcessor.Default.cs @@ -0,0 +1,70 @@ +using System; +using System.Collections.Generic; +using System.Text; +using System.Threading.Tasks; +using Dapper; +using DotNetCore.CAP.Processor; +using Microsoft.Extensions.DependencyInjection; +using Microsoft.Extensions.Logging; + +namespace DotNetCore.CAP.EntityFrameworkCore +{ + public class DefaultAdditionalProcessor : IAdditionalProcessor + { + private readonly IServiceProvider _provider; + private readonly ILogger _logger; + private readonly SqlServerOptions _options; + + private const int MaxBatch = 1000; + private readonly TimeSpan _delay = TimeSpan.FromSeconds(1); + private readonly TimeSpan _waitingInterval = TimeSpan.FromHours(2); + + private static readonly string[] Tables = + { + nameof(CapDbContext.CapSentMessages), + nameof(CapDbContext.CapReceivedMessages), + }; + + public DefaultAdditionalProcessor( + IServiceProvider provider, + ILogger logger, + SqlServerOptions sqlServerOptions) + { + _logger = logger; + _provider = provider; + _options = sqlServerOptions; + } + + public async Task ProcessAsync(ProcessingContext context) + { + _logger.LogDebug("Collecting expired entities."); + + foreach (var table in Tables) + { + var removedCount = 0; + do + { + using (var scope = _provider.CreateScope()) + { + var provider = scope.ServiceProvider; + var jobsDbContext = provider.GetService(); + var connection = jobsDbContext.GetDbConnection(); + + removedCount = await connection.ExecuteAsync($@" +DELETE TOP (@count) +FROM [{_options.Schema}].[{table}] WITH (readpast) +WHERE ExpiresAt < @now;", new { now = DateTime.Now, count = MaxBatch }); + } + + if (removedCount != 0) + { + await context.WaitAsync(_delay); + context.ThrowIfStopping(); + } + } while (removedCount != 0); + } + + await context.WaitAsync(_waitingInterval); + } + } +} diff --git a/src/DotNetCore.CAP.Kafka/CAP.BuilderExtensions.cs b/src/DotNetCore.CAP.Kafka/CAP.BuilderExtensions.cs index 4c3375e..4f064b4 100644 --- a/src/DotNetCore.CAP.Kafka/CAP.BuilderExtensions.cs +++ b/src/DotNetCore.CAP.Kafka/CAP.BuilderExtensions.cs @@ -1,6 +1,5 @@ using System; using DotNetCore.CAP; -using DotNetCore.CAP.Job; using DotNetCore.CAP.Kafka; namespace Microsoft.Extensions.DependencyInjection @@ -24,7 +23,7 @@ namespace Microsoft.Extensions.DependencyInjection builder.Services.AddSingleton(); - builder.Services.AddTransient(); + builder.Services.AddTransient(); return builder; } diff --git a/src/DotNetCore.CAP.Kafka/PublishQueueExecutor.cs b/src/DotNetCore.CAP.Kafka/PublishQueueExecutor.cs new file mode 100644 index 0000000..e54975b --- /dev/null +++ b/src/DotNetCore.CAP.Kafka/PublishQueueExecutor.cs @@ -0,0 +1,54 @@ +using System; +using System.Text; +using System.Threading.Tasks; +using Confluent.Kafka; +using Confluent.Kafka.Serialization; +using DotNetCore.CAP.Processor.States; +using Microsoft.Extensions.Logging; +using Microsoft.Extensions.Options; + +namespace DotNetCore.CAP.Kafka +{ + public class PublishQueueExecutor : BasePublishQueueExecutor + { + private readonly ILogger _logger; + private readonly KafkaOptions _kafkaOptions; + + public PublishQueueExecutor(IStateChanger stateChanger, + IOptions options, + ILogger logger) + : base(stateChanger, logger) + { + _logger = logger; + _kafkaOptions = options.Value; + } + + public override Task PublishAsync(string keyName, string content) + { + try + { + var config = _kafkaOptions.AsRdkafkaConfig(); + using (var producer = new Producer(config, null, new StringSerializer(Encoding.UTF8))) + { + producer.ProduceAsync(keyName, null, content); + producer.Flush(); + } + + _logger.LogDebug($"kafka topic message [{keyName}] has been published."); + + return Task.FromResult(OperateResult.Success); + } + catch (Exception ex) + { + _logger.LogError($"kafka topic message [{keyName}] has benn raised an exception of sending. the exception is: {ex.Message}"); + + return Task.FromResult(OperateResult.Failed(ex, + new OperateError() + { + Code = ex.HResult.ToString(), + Description = ex.Message + })); + } + } + } +} diff --git a/src/DotNetCore.CAP.RabbitMQ/CAP.BuilderExtensions.cs b/src/DotNetCore.CAP.RabbitMQ/CAP.BuilderExtensions.cs index 2afb79e..2a92956 100644 --- a/src/DotNetCore.CAP.RabbitMQ/CAP.BuilderExtensions.cs +++ b/src/DotNetCore.CAP.RabbitMQ/CAP.BuilderExtensions.cs @@ -1,6 +1,5 @@ using System; using DotNetCore.CAP; -using DotNetCore.CAP.Job; using DotNetCore.CAP.RabbitMQ; namespace Microsoft.Extensions.DependencyInjection @@ -15,7 +14,7 @@ namespace Microsoft.Extensions.DependencyInjection builder.Services.AddSingleton(); - builder.Services.AddTransient(); + builder.Services.AddTransient(); return builder; } diff --git a/src/DotNetCore.CAP.RabbitMQ/PublishQueueExecutor.cs b/src/DotNetCore.CAP.RabbitMQ/PublishQueueExecutor.cs new file mode 100644 index 0000000..df08dd2 --- /dev/null +++ b/src/DotNetCore.CAP.RabbitMQ/PublishQueueExecutor.cs @@ -0,0 +1,70 @@ +using System; +using System.Text; +using System.Threading.Tasks; +using DotNetCore.CAP.Processor.States; +using Microsoft.Extensions.Logging; +using Microsoft.Extensions.Options; +using RabbitMQ.Client; + +namespace DotNetCore.CAP.RabbitMQ +{ + public class PublishQueueExecutor : BasePublishQueueExecutor + { + private readonly ILogger _logger; + private readonly RabbitMQOptions _rabbitMqOptions; + + public PublishQueueExecutor(IStateChanger stateChanger, + IOptions options, + ILogger logger) + : base(stateChanger, logger) + { + _logger = logger; + _rabbitMqOptions = options.Value; + } + + public override Task PublishAsync(string keyName, string content) + { + var factory = new ConnectionFactory() + { + HostName = _rabbitMqOptions.HostName, + UserName = _rabbitMqOptions.UserName, + Port = _rabbitMqOptions.Port, + Password = _rabbitMqOptions.Password, + VirtualHost = _rabbitMqOptions.VirtualHost, + RequestedConnectionTimeout = _rabbitMqOptions.RequestedConnectionTimeout, + SocketReadTimeout = _rabbitMqOptions.SocketReadTimeout, + SocketWriteTimeout = _rabbitMqOptions.SocketWriteTimeout + }; + + try + { + using (var connection = factory.CreateConnection()) + using (var channel = connection.CreateModel()) + { + var body = Encoding.UTF8.GetBytes(content); + + channel.ExchangeDeclare(_rabbitMqOptions.TopicExchangeName, _rabbitMqOptions.EXCHANGE_TYPE); + channel.BasicPublish(exchange: _rabbitMqOptions.TopicExchangeName, + routingKey: keyName, + basicProperties: null, + body: body); + + _logger.LogDebug($"rabbitmq topic message [{keyName}] has been published."); + } + return Task.FromResult(OperateResult.Success); + } + catch (Exception ex) + { + _logger.LogError($"rabbitmq topic message [{keyName}] has benn raised an exception of sending. the exception is: {ex.Message}"); + + return Task.FromResult(OperateResult.Failed(ex, + new OperateError() + { + Code = ex.HResult.ToString(), + Description = ex.Message + })); + } + + } + } +} diff --git a/src/DotNetCore.CAP/CAP.Builder.cs b/src/DotNetCore.CAP/CAP.Builder.cs index 582678a..6214c12 100644 --- a/src/DotNetCore.CAP/CAP.Builder.cs +++ b/src/DotNetCore.CAP/CAP.Builder.cs @@ -1,5 +1,4 @@ using System; -using DotNetCore.CAP.Job; using Microsoft.Extensions.DependencyInjection; namespace DotNetCore.CAP diff --git a/src/DotNetCore.CAP/CAP.ServiceCollectionExtensions.cs b/src/DotNetCore.CAP/CAP.ServiceCollectionExtensions.cs index 208b635..e38bd2b 100644 --- a/src/DotNetCore.CAP/CAP.ServiceCollectionExtensions.cs +++ b/src/DotNetCore.CAP/CAP.ServiceCollectionExtensions.cs @@ -6,8 +6,8 @@ using DotNetCore.CAP.Abstractions; using DotNetCore.CAP.Abstractions.ModelBinding; using DotNetCore.CAP.Infrastructure; using DotNetCore.CAP.Internal; -using DotNetCore.CAP.Job; -using DotNetCore.CAP.Job.States; +using DotNetCore.CAP.Processor; +using DotNetCore.CAP.Processor.States; using Microsoft.Extensions.DependencyInjection.Extensions; namespace Microsoft.Extensions.DependencyInjection @@ -48,12 +48,16 @@ namespace Microsoft.Extensions.DependencyInjection services.TryAddSingleton(); services.AddSingleton(); - services.AddSingleton(); + services.AddSingleton(); services.AddSingleton(); services.AddSingleton(); + //Processors - services.AddTransient(); - + services.AddTransient(); + services.AddTransient(); + services.AddTransient(); + + //Executors services.AddSingleton(); services.AddSingleton(); diff --git a/src/DotNetCore.CAP/DotNetCore.CAP.csproj b/src/DotNetCore.CAP/DotNetCore.CAP.csproj index ffbf70e..a59f6cd 100644 --- a/src/DotNetCore.CAP/DotNetCore.CAP.csproj +++ b/src/DotNetCore.CAP/DotNetCore.CAP.csproj @@ -15,7 +15,7 @@ - + diff --git a/src/DotNetCore.CAP/IBootstrapper.Default.cs b/src/DotNetCore.CAP/IBootstrapper.Default.cs index 7f25780..58bfe58 100644 --- a/src/DotNetCore.CAP/IBootstrapper.Default.cs +++ b/src/DotNetCore.CAP/IBootstrapper.Default.cs @@ -2,7 +2,6 @@ using System.Collections.Generic; using System.Threading; using System.Threading.Tasks; -using DotNetCore.CAP.Infrastructure; using Microsoft.AspNetCore.Hosting; using Microsoft.Extensions.DependencyInjection; using Microsoft.Extensions.Logging; diff --git a/src/DotNetCore.CAP/IConsumerHandler.Default.cs b/src/DotNetCore.CAP/IConsumerHandler.Default.cs index 1322b17..d84a669 100644 --- a/src/DotNetCore.CAP/IConsumerHandler.Default.cs +++ b/src/DotNetCore.CAP/IConsumerHandler.Default.cs @@ -6,6 +6,7 @@ using DotNetCore.CAP.Abstractions; using DotNetCore.CAP.Infrastructure; using DotNetCore.CAP.Internal; using DotNetCore.CAP.Models; +using DotNetCore.CAP.Processor; using Microsoft.Extensions.DependencyInjection; using Microsoft.Extensions.Logging; using Microsoft.Extensions.Options; @@ -106,7 +107,6 @@ namespace DotNetCore.CAP { var receviedMessage = StoreMessage(scope, message); client.Commit(); - // ProcessMessage(scope, receviedMessage); } }; } @@ -125,40 +125,7 @@ namespace DotNetCore.CAP public void Pulse() { - WaitHandleEx.ReceviedPulseEvent.Set(); + SubscribeQueuer.PulseEvent.Set(); } - - //private void ProcessMessage(IServiceScope serviceScope, CapReceivedMessage receivedMessage) - //{ - // var provider = serviceScope.ServiceProvider; - // var messageStore = provider.GetRequiredService(); - // try - // { - // var executeDescriptorGroup = _selector.GetTopicExector(receivedMessage.KeyName); - - // if (executeDescriptorGroup.ContainsKey(receivedMessage.Group)) - // { - // messageStore.FetchNextReceivedMessageAsync - - - - // messageStore.ChangeReceivedMessageStateAsync(receivedMessage, StatusName.Processing).Wait(); - - // // If there are multiple consumers in the same group, we will take the first - // var executeDescriptor = executeDescriptorGroup[receivedMessage.Group][0]; - // var consumerContext = new ConsumerContext(executeDescriptor, receivedMessage.ToMessageContext()); - - // _consumerInvokerFactory.CreateInvoker(consumerContext).InvokeAsync(); - - // messageStore.ChangeReceivedMessageStateAsync(receivedMessage, StatusName.Succeeded).Wait(); - // } - // } - // catch (Exception ex) - // { - // _logger.ConsumerMethodExecutingFailed($"Group:{receivedMessage.Group}, Topic:{receivedMessage.KeyName}", ex); - // } - //} - - } } \ No newline at end of file diff --git a/src/DotNetCore.CAP/IQueueExecutor.Publish.Base.cs b/src/DotNetCore.CAP/IQueueExecutor.Publish.Base.cs index 521b9f8..09f7d40 100644 --- a/src/DotNetCore.CAP/IQueueExecutor.Publish.Base.cs +++ b/src/DotNetCore.CAP/IQueueExecutor.Publish.Base.cs @@ -3,8 +3,8 @@ using System.Collections.Generic; using System.Diagnostics; using System.Text; using System.Threading.Tasks; -using DotNetCore.CAP.Job; -using DotNetCore.CAP.Job.States; +using DotNetCore.CAP.Processor; +using DotNetCore.CAP.Processor.States; using DotNetCore.CAP.Models; using Microsoft.Extensions.Logging; @@ -93,7 +93,7 @@ namespace DotNetCore.CAP } var due = message.Added.AddSeconds(retryBehavior.RetryIn(retries)); - message.LastRun = due; + message.ExpiresAt = due; using (var transaction = connection.CreateTransaction()) { transaction.UpdateMessage(message); diff --git a/src/DotNetCore.CAP/IQueueExecutor.Subscibe.cs b/src/DotNetCore.CAP/IQueueExecutor.Subscibe.cs index 31cc863..d69cdf4 100644 --- a/src/DotNetCore.CAP/IQueueExecutor.Subscibe.cs +++ b/src/DotNetCore.CAP/IQueueExecutor.Subscibe.cs @@ -7,8 +7,8 @@ using System.Threading.Tasks; using DotNetCore.CAP.Abstractions; using DotNetCore.CAP.Infrastructure; using DotNetCore.CAP.Internal; -using DotNetCore.CAP.Job; -using DotNetCore.CAP.Job.States; +using DotNetCore.CAP.Processor; +using DotNetCore.CAP.Processor.States; using DotNetCore.CAP.Models; using Microsoft.Extensions.Logging; @@ -22,7 +22,7 @@ namespace DotNetCore.CAP private readonly ILogger _logger; private readonly MethodMatcherCache _selector; - private readonly CapOptions _options; + //private readonly CapOptions _options; public SubscibeQueueExecutor( IStateChanger stateChanger, @@ -132,7 +132,7 @@ namespace DotNetCore.CAP { var retryBehavior = RetryBehavior.DefaultRetry; - var now = DateTime.UtcNow; + var now = DateTime.Now; var retries = ++message.Retries; if (retries >= retryBehavior.RetryCount) { @@ -140,7 +140,7 @@ namespace DotNetCore.CAP } var due = message.Added.AddSeconds(retryBehavior.RetryIn(retries)); - message.LastRun = due; + message.ExpiresAt = due; using (var transaction = connection.CreateTransaction()) { transaction.UpdateMessage(message); diff --git a/src/DotNetCore.CAP/Infrastructure/WaitHandleEx.cs b/src/DotNetCore.CAP/Infrastructure/WaitHandleEx.cs index 24cfbdf..5a277d2 100644 --- a/src/DotNetCore.CAP/Infrastructure/WaitHandleEx.cs +++ b/src/DotNetCore.CAP/Infrastructure/WaitHandleEx.cs @@ -6,11 +6,6 @@ namespace DotNetCore.CAP.Infrastructure { public static class WaitHandleEx { - public static readonly AutoResetEvent PulseEvent = new AutoResetEvent(true); - public static readonly AutoResetEvent QueuePulseEvent = new AutoResetEvent(true); - public static readonly AutoResetEvent SentPulseEvent = new AutoResetEvent(true); - public static readonly AutoResetEvent ReceviedPulseEvent = new AutoResetEvent(true); - public static Task WaitAnyAsync(WaitHandle handle1, WaitHandle handle2, TimeSpan timeout) { var t1 = handle1.WaitOneAsync(timeout); diff --git a/src/DotNetCore.CAP/LoggerExtensions.cs b/src/DotNetCore.CAP/LoggerExtensions.cs index 0d1894a..5bb3ee5 100644 --- a/src/DotNetCore.CAP/LoggerExtensions.cs +++ b/src/DotNetCore.CAP/LoggerExtensions.cs @@ -1,7 +1,7 @@ using System; using System.Collections.Generic; using System.Linq; -using DotNetCore.CAP.Job; +using DotNetCore.CAP.Processor; using Microsoft.Extensions.Logging; namespace DotNetCore.CAP diff --git a/src/DotNetCore.CAP/Models/CapReceivedMessage.cs b/src/DotNetCore.CAP/Models/CapReceivedMessage.cs index ce1df51..dfa5624 100644 --- a/src/DotNetCore.CAP/Models/CapReceivedMessage.cs +++ b/src/DotNetCore.CAP/Models/CapReceivedMessage.cs @@ -34,7 +34,7 @@ namespace DotNetCore.CAP.Models public DateTime Added { get; set; } - public DateTime? LastRun { get; set; } + public DateTime? ExpiresAt { get; set; } public int Retries { get; set; } diff --git a/src/DotNetCore.CAP/Models/CapSentMessage.cs b/src/DotNetCore.CAP/Models/CapSentMessage.cs index f615fa7..6752536 100644 --- a/src/DotNetCore.CAP/Models/CapSentMessage.cs +++ b/src/DotNetCore.CAP/Models/CapSentMessage.cs @@ -31,7 +31,7 @@ namespace DotNetCore.CAP.Models public DateTime Added { get; set; } - public DateTime? LastRun { get; set; } + public DateTime? ExpiresAt { get; set; } public int Retries { get; set; } diff --git a/test/DotNetCore.CAP.Test/CAP.BuilderTest.cs b/test/DotNetCore.CAP.Test/CAP.BuilderTest.cs index 7d48704..6289ee2 100644 --- a/test/DotNetCore.CAP.Test/CAP.BuilderTest.cs +++ b/test/DotNetCore.CAP.Test/CAP.BuilderTest.cs @@ -1,7 +1,7 @@ using System; using System.Threading; using System.Threading.Tasks; -using DotNetCore.CAP.Job; +using DotNetCore.CAP.Processor; using DotNetCore.CAP.Models; using Microsoft.Extensions.DependencyInjection; using Xunit; diff --git a/test/DotNetCore.CAP.Test/Job/ComputedJobTest.cs b/test/DotNetCore.CAP.Test/Job/ComputedJobTest.cs index 731851b..a69e0fd 100644 --- a/test/DotNetCore.CAP.Test/Job/ComputedJobTest.cs +++ b/test/DotNetCore.CAP.Test/Job/ComputedJobTest.cs @@ -1,7 +1,7 @@ //using System; //using System.Collections.Generic; //using System.Text; -//using DotNetCore.CAP.Job; +//using DotNetCore.CAP.Processor; //using Xunit; //namespace DotNetCore.CAP.Test.Job diff --git a/test/DotNetCore.CAP.Test/Job/JobProcessingServerTest.cs b/test/DotNetCore.CAP.Test/Job/JobProcessingServerTest.cs index 105dd13..cfc498d 100644 --- a/test/DotNetCore.CAP.Test/Job/JobProcessingServerTest.cs +++ b/test/DotNetCore.CAP.Test/Job/JobProcessingServerTest.cs @@ -4,7 +4,7 @@ //using System.Threading; //using System.Threading.Tasks; //using DotNetCore.CAP.Infrastructure; -//using DotNetCore.CAP.Job; +//using DotNetCore.CAP.Processor; //using Microsoft.Extensions.DependencyInjection; //using Moq; //using Xunit; From c1c4a2bf39bdd1c15f25f4b575cb93dc46eea158 Mon Sep 17 00:00:00 2001 From: yangxiaodong Date: Fri, 14 Jul 2017 18:30:10 +0800 Subject: [PATCH 12/68] create new migrations files. --- ...ner.cs => 20170714102709_InitializeDB.Designer.cs} | 11 ++++++----- ...InitializeDB.cs => 20170714102709_InitializeDB.cs} | 4 ++-- .../Migrations/CapDbContextModelSnapshot.cs | 9 +++++---- 3 files changed, 13 insertions(+), 11 deletions(-) rename src/DotNetCore.CAP.EntityFrameworkCore/Migrations/{20170711154104_InitializeDB.Designer.cs => 20170714102709_InitializeDB.Designer.cs} (93%) rename src/DotNetCore.CAP.EntityFrameworkCore/Migrations/{20170711154104_InitializeDB.cs => 20170714102709_InitializeDB.cs} (96%) diff --git a/src/DotNetCore.CAP.EntityFrameworkCore/Migrations/20170711154104_InitializeDB.Designer.cs b/src/DotNetCore.CAP.EntityFrameworkCore/Migrations/20170714102709_InitializeDB.Designer.cs similarity index 93% rename from src/DotNetCore.CAP.EntityFrameworkCore/Migrations/20170711154104_InitializeDB.Designer.cs rename to src/DotNetCore.CAP.EntityFrameworkCore/Migrations/20170714102709_InitializeDB.Designer.cs index 0f9da26..5d5fb40 100644 --- a/src/DotNetCore.CAP.EntityFrameworkCore/Migrations/20170711154104_InitializeDB.Designer.cs +++ b/src/DotNetCore.CAP.EntityFrameworkCore/Migrations/20170714102709_InitializeDB.Designer.cs @@ -4,11 +4,12 @@ using Microsoft.EntityFrameworkCore.Infrastructure; using Microsoft.EntityFrameworkCore.Metadata; using Microsoft.EntityFrameworkCore.Migrations; using DotNetCore.CAP.EntityFrameworkCore; +using DotNetCore.CAP.Models; namespace DotNetCore.CAP.EntityFrameworkCore.Migrations { [DbContext(typeof(CapDbContext))] - [Migration("20170711154104_InitializeDB")] + [Migration("20170714102709_InitializeDB")] partial class InitializeDB { protected override void BuildTargetModel(ModelBuilder modelBuilder) @@ -41,12 +42,12 @@ namespace DotNetCore.CAP.EntityFrameworkCore.Migrations b.Property("Content"); + b.Property("ExpiresAt"); + b.Property("Group"); b.Property("KeyName"); - b.Property("LastRun"); - b.Property("Retries"); b.Property("StatusName") @@ -69,9 +70,9 @@ namespace DotNetCore.CAP.EntityFrameworkCore.Migrations b.Property("Content"); - b.Property("KeyName"); + b.Property("ExpiresAt"); - b.Property("LastRun"); + b.Property("KeyName"); b.Property("Retries"); diff --git a/src/DotNetCore.CAP.EntityFrameworkCore/Migrations/20170711154104_InitializeDB.cs b/src/DotNetCore.CAP.EntityFrameworkCore/Migrations/20170714102709_InitializeDB.cs similarity index 96% rename from src/DotNetCore.CAP.EntityFrameworkCore/Migrations/20170711154104_InitializeDB.cs rename to src/DotNetCore.CAP.EntityFrameworkCore/Migrations/20170714102709_InitializeDB.cs index dd96f24..4607b1e 100644 --- a/src/DotNetCore.CAP.EntityFrameworkCore/Migrations/20170711154104_InitializeDB.cs +++ b/src/DotNetCore.CAP.EntityFrameworkCore/Migrations/20170714102709_InitializeDB.cs @@ -35,9 +35,9 @@ namespace DotNetCore.CAP.EntityFrameworkCore.Migrations Id = table.Column(nullable: false), Added = table.Column(nullable: false), Content = table.Column(nullable: true), + ExpiresAt = table.Column(nullable: true), Group = table.Column(nullable: true), KeyName = table.Column(nullable: true), - LastRun = table.Column(nullable: true), Retries = table.Column(nullable: false), StatusName = table.Column(maxLength: 50, nullable: false) }, @@ -54,8 +54,8 @@ namespace DotNetCore.CAP.EntityFrameworkCore.Migrations Id = table.Column(nullable: false), Added = table.Column(nullable: false), Content = table.Column(nullable: true), + ExpiresAt = table.Column(nullable: true), KeyName = table.Column(nullable: true), - LastRun = table.Column(nullable: true), Retries = table.Column(nullable: false), StatusName = table.Column(maxLength: 50, nullable: false) }, diff --git a/src/DotNetCore.CAP.EntityFrameworkCore/Migrations/CapDbContextModelSnapshot.cs b/src/DotNetCore.CAP.EntityFrameworkCore/Migrations/CapDbContextModelSnapshot.cs index 765fa0f..63f1770 100644 --- a/src/DotNetCore.CAP.EntityFrameworkCore/Migrations/CapDbContextModelSnapshot.cs +++ b/src/DotNetCore.CAP.EntityFrameworkCore/Migrations/CapDbContextModelSnapshot.cs @@ -4,6 +4,7 @@ using Microsoft.EntityFrameworkCore.Infrastructure; using Microsoft.EntityFrameworkCore.Metadata; using Microsoft.EntityFrameworkCore.Migrations; using DotNetCore.CAP.EntityFrameworkCore; +using DotNetCore.CAP.Models; namespace DotNetCore.CAP.EntityFrameworkCore.Migrations { @@ -40,12 +41,12 @@ namespace DotNetCore.CAP.EntityFrameworkCore.Migrations b.Property("Content"); + b.Property("ExpiresAt"); + b.Property("Group"); b.Property("KeyName"); - b.Property("LastRun"); - b.Property("Retries"); b.Property("StatusName") @@ -68,9 +69,9 @@ namespace DotNetCore.CAP.EntityFrameworkCore.Migrations b.Property("Content"); - b.Property("KeyName"); + b.Property("ExpiresAt"); - b.Property("LastRun"); + b.Property("KeyName"); b.Property("Retries"); From a04076d2287b622266b715e560f6b291d38931ae Mon Sep 17 00:00:00 2001 From: yangxiaodong Date: Fri, 14 Jul 2017 18:30:42 +0800 Subject: [PATCH 13/68] remove unused files. --- src/DotNetCore.CAP.Kafka/LoggerExtensions.cs | 125 ------------------ .../LoggerExtensions.cs | 125 ------------------ 2 files changed, 250 deletions(-) delete mode 100644 src/DotNetCore.CAP.Kafka/LoggerExtensions.cs delete mode 100644 src/DotNetCore.CAP.RabbitMQ/LoggerExtensions.cs diff --git a/src/DotNetCore.CAP.Kafka/LoggerExtensions.cs b/src/DotNetCore.CAP.Kafka/LoggerExtensions.cs deleted file mode 100644 index 1dec1c7..0000000 --- a/src/DotNetCore.CAP.Kafka/LoggerExtensions.cs +++ /dev/null @@ -1,125 +0,0 @@ -using System; -using Microsoft.Extensions.Logging; - -namespace DotNetCore.CAP.Kafka -{ - internal static class LoggerExtensions - { - private static readonly Action _collectingExpiredEntities; - - private static readonly Action _installing; - private static readonly Action _installingError; - private static readonly Action _installingSuccess; - - private static readonly Action _jobFailed; - private static readonly Action _jobFailedWillRetry; - private static readonly Action _jobExecuted; - private static readonly Action _jobRetrying; - private static readonly Action _jobCouldNotBeLoaded; - private static readonly Action _exceptionOccuredWhileExecutingJob; - - static LoggerExtensions() - { - _collectingExpiredEntities = LoggerMessage.Define( - LogLevel.Debug, - 1, - "Collecting expired entities."); - - _installing = LoggerMessage.Define( - LogLevel.Debug, - 1, - "Installing Jobs SQL objects..."); - - _installingError = LoggerMessage.Define( - LogLevel.Warning, - 2, - "Exception occurred during automatic migration. Retrying..."); - - _installingSuccess = LoggerMessage.Define( - LogLevel.Debug, - 3, - "Jobs SQL objects installed."); - - _jobFailed = LoggerMessage.Define( - LogLevel.Warning, - 1, - "Job failed to execute."); - - _jobFailedWillRetry = LoggerMessage.Define( - LogLevel.Warning, - 2, - "Job failed to execute. Will retry."); - - _jobRetrying = LoggerMessage.Define( - LogLevel.Debug, - 3, - "Retrying a job: {Retries}..."); - - _jobExecuted = LoggerMessage.Define( - LogLevel.Debug, - 4, - "Job executed. Took: {Seconds} secs."); - - _jobCouldNotBeLoaded = LoggerMessage.Define( - LogLevel.Warning, - 5, - "Could not load a job: '{JobId}'."); - - _exceptionOccuredWhileExecutingJob = LoggerMessage.Define( - LogLevel.Error, - 6, - "An exception occured while trying to execute a job: '{JobId}'. " + - "Requeuing for another retry."); - } - - public static void CollectingExpiredEntities(this ILogger logger) - { - _collectingExpiredEntities(logger, null); - } - - public static void Installing(this ILogger logger) - { - _installing(logger, null); - } - - public static void InstallingError(this ILogger logger, Exception ex) - { - _installingError(logger, ex); - } - - public static void InstallingSuccess(this ILogger logger) - { - _installingSuccess(logger, null); - } - - public static void JobFailed(this ILogger logger, Exception ex) - { - _jobFailed(logger, ex); - } - - public static void JobFailedWillRetry(this ILogger logger, Exception ex) - { - _jobFailedWillRetry(logger, ex); - } - - public static void JobRetrying(this ILogger logger, int retries) - { - _jobRetrying(logger, retries, null); - } - - public static void JobExecuted(this ILogger logger, double seconds) - { - _jobExecuted(logger, seconds, null); - } - - public static void JobCouldNotBeLoaded(this ILogger logger, int jobId, Exception ex) - { - _jobCouldNotBeLoaded(logger, jobId, ex); - } - - public static void ExceptionOccuredWhileExecutingJob(this ILogger logger, string jobId, Exception ex) - { - _exceptionOccuredWhileExecutingJob(logger, jobId, ex); - } - } -} \ No newline at end of file diff --git a/src/DotNetCore.CAP.RabbitMQ/LoggerExtensions.cs b/src/DotNetCore.CAP.RabbitMQ/LoggerExtensions.cs deleted file mode 100644 index f264326..0000000 --- a/src/DotNetCore.CAP.RabbitMQ/LoggerExtensions.cs +++ /dev/null @@ -1,125 +0,0 @@ -using System; -using Microsoft.Extensions.Logging; - -namespace DotNetCore.CAP.RabbitMQ -{ - internal static class LoggerExtensions - { - private static Action _collectingExpiredEntities; - - private static Action _installing; - private static Action _installingError; - private static Action _installingSuccess; - - private static Action _jobFailed; - private static Action _jobFailedWillRetry; - private static Action _jobExecuted; - private static Action _jobRetrying; - private static Action _jobCouldNotBeLoaded; - private static Action _exceptionOccuredWhileExecutingJob; - - static LoggerExtensions() - { - _collectingExpiredEntities = LoggerMessage.Define( - LogLevel.Debug, - 1, - "Collecting expired entities."); - - _installing = LoggerMessage.Define( - LogLevel.Debug, - 1, - "Installing Jobs SQL objects..."); - - _installingError = LoggerMessage.Define( - LogLevel.Warning, - 2, - "Exception occurred during automatic migration. Retrying..."); - - _installingSuccess = LoggerMessage.Define( - LogLevel.Debug, - 3, - "Jobs SQL objects installed."); - - _jobFailed = LoggerMessage.Define( - LogLevel.Warning, - 1, - "Job failed to execute."); - - _jobFailedWillRetry = LoggerMessage.Define( - LogLevel.Warning, - 2, - "Job failed to execute. Will retry."); - - _jobRetrying = LoggerMessage.Define( - LogLevel.Debug, - 3, - "Retrying a job: {Retries}..."); - - _jobExecuted = LoggerMessage.Define( - LogLevel.Debug, - 4, - "Job executed. Took: {Seconds} secs."); - - _jobCouldNotBeLoaded = LoggerMessage.Define( - LogLevel.Warning, - 5, - "Could not load a job: '{JobId}'."); - - _exceptionOccuredWhileExecutingJob = LoggerMessage.Define( - LogLevel.Error, - 6, - "An exception occured while trying to execute a job: '{JobId}'. " + - "Requeuing for another retry."); - } - - public static void CollectingExpiredEntities(this ILogger logger) - { - _collectingExpiredEntities(logger, null); - } - - public static void Installing(this ILogger logger) - { - _installing(logger, null); - } - - public static void InstallingError(this ILogger logger, Exception ex) - { - _installingError(logger, ex); - } - - public static void InstallingSuccess(this ILogger logger) - { - _installingSuccess(logger, null); - } - - public static void JobFailed(this ILogger logger, Exception ex) - { - _jobFailed(logger, ex); - } - - public static void JobFailedWillRetry(this ILogger logger, Exception ex) - { - _jobFailedWillRetry(logger, ex); - } - - public static void JobRetrying(this ILogger logger, int retries) - { - _jobRetrying(logger, retries, null); - } - - public static void JobExecuted(this ILogger logger, double seconds) - { - _jobExecuted(logger, seconds, null); - } - - public static void JobCouldNotBeLoaded(this ILogger logger, int jobId, Exception ex) - { - _jobCouldNotBeLoaded(logger, jobId, ex); - } - - public static void ExceptionOccuredWhileExecutingJob(this ILogger logger, string jobId, Exception ex) - { - _exceptionOccuredWhileExecutingJob(logger, jobId, ex); - } - } -} \ No newline at end of file From 3ec25195e70364f7932bd56566644d001c19bd95 Mon Sep 17 00:00:00 2001 From: yangxiaodong Date: Fri, 14 Jul 2017 18:31:01 +0800 Subject: [PATCH 14/68] add dbcontext type to options. --- .../CAP.BuilderExtensions.cs | 3 ++- src/DotNetCore.CAP.EntityFrameworkCore/CapDbContext.cs | 5 +++-- .../CapPublisherExtensions.cs | 2 +- .../EFStorageConnection.cs | 10 +++++----- .../SqlServerOptions.cs | 2 ++ 5 files changed, 13 insertions(+), 9 deletions(-) diff --git a/src/DotNetCore.CAP.EntityFrameworkCore/CAP.BuilderExtensions.cs b/src/DotNetCore.CAP.EntityFrameworkCore/CAP.BuilderExtensions.cs index 668f090..c12ae54 100644 --- a/src/DotNetCore.CAP.EntityFrameworkCore/CAP.BuilderExtensions.cs +++ b/src/DotNetCore.CAP.EntityFrameworkCore/CAP.BuilderExtensions.cs @@ -28,6 +28,7 @@ namespace Microsoft.Extensions.DependencyInjection builder.Services.Configure(actionOptions); var sqlServerOptions = new SqlServerOptions(); + sqlServerOptions.DbContextType = typeof(TContext); actionOptions(sqlServerOptions); builder.Services.AddSingleton(sqlServerOptions); @@ -44,6 +45,6 @@ namespace Microsoft.Extensions.DependencyInjection return builder; } - + } } \ No newline at end of file diff --git a/src/DotNetCore.CAP.EntityFrameworkCore/CapDbContext.cs b/src/DotNetCore.CAP.EntityFrameworkCore/CapDbContext.cs index 3b861d1..882e742 100644 --- a/src/DotNetCore.CAP.EntityFrameworkCore/CapDbContext.cs +++ b/src/DotNetCore.CAP.EntityFrameworkCore/CapDbContext.cs @@ -28,8 +28,7 @@ namespace DotNetCore.CAP.EntityFrameworkCore /// /// Gets or sets the of Messages. /// - public DbSet CapSentMessages { get; set; } - + public DbSet CapSentMessages { get; set; } public DbSet CapQueue { get; set; } @@ -48,6 +47,7 @@ namespace DotNetCore.CAP.EntityFrameworkCore /// protected override void OnModelCreating(ModelBuilder modelBuilder) { + //_sqlServerOptions = new SqlServerOptions(); modelBuilder.HasDefaultSchema(_sqlServerOptions.Schema); modelBuilder.Entity(b => @@ -67,6 +67,7 @@ namespace DotNetCore.CAP.EntityFrameworkCore protected override void OnConfiguring(DbContextOptionsBuilder optionsBuilder) { + // optionsBuilder.UseSqlServer("Server=192.168.2.206;Initial Catalog=Test;User Id=cmswuliu;Password=h7xY81agBn*Veiu3;MultipleActiveResultSets=True"); } } } \ No newline at end of file diff --git a/src/DotNetCore.CAP.EntityFrameworkCore/CapPublisherExtensions.cs b/src/DotNetCore.CAP.EntityFrameworkCore/CapPublisherExtensions.cs index ad9d5be..0d4a4b6 100644 --- a/src/DotNetCore.CAP.EntityFrameworkCore/CapPublisherExtensions.cs +++ b/src/DotNetCore.CAP.EntityFrameworkCore/CapPublisherExtensions.cs @@ -32,7 +32,7 @@ namespace DotNetCore.CAP } - public static async Task Publish(this ICapPublisher publisher, string topic, string content, IDbConnection connection,IDbTransaction transaction) + public static async Task Publish(this ICapPublisher publisher, string topic, string content, IDbConnection connection, IDbTransaction transaction) { var message = new CapSentMessage { diff --git a/src/DotNetCore.CAP.EntityFrameworkCore/EFStorageConnection.cs b/src/DotNetCore.CAP.EntityFrameworkCore/EFStorageConnection.cs index f996028..b8e278e 100644 --- a/src/DotNetCore.CAP.EntityFrameworkCore/EFStorageConnection.cs +++ b/src/DotNetCore.CAP.EntityFrameworkCore/EFStorageConnection.cs @@ -108,14 +108,14 @@ WHERE StateName = '{StatusName.Enqueued}'"; private async Task FetchNextMessageCoreAsync(string sql, object args = null) { - FetchedMessage fetchedJob = null; + FetchedMessage fetchedMessage = null; var connection = _context.GetDbConnection(); var transaction = _context.Database.CurrentTransaction; transaction = transaction ?? await _context.Database.BeginTransactionAsync(IsolationLevel.ReadCommitted); try { - fetchedJob = + fetchedMessage = (await connection.QueryAsync(sql, args, transaction.GetDbTransaction())) .FirstOrDefault(); } @@ -125,7 +125,7 @@ WHERE StateName = '{StatusName.Enqueued}'"; throw; } - if (fetchedJob == null) + if (fetchedMessage == null) { transaction.Rollback(); transaction.Dispose(); @@ -133,8 +133,8 @@ WHERE StateName = '{StatusName.Enqueued}'"; } return new EFFetchedMessage( - fetchedJob.MessageId, - fetchedJob.Type, + fetchedMessage.MessageId, + fetchedMessage.Type, connection, transaction); } diff --git a/src/DotNetCore.CAP.EntityFrameworkCore/SqlServerOptions.cs b/src/DotNetCore.CAP.EntityFrameworkCore/SqlServerOptions.cs index 4f6532e..03aebd3 100644 --- a/src/DotNetCore.CAP.EntityFrameworkCore/SqlServerOptions.cs +++ b/src/DotNetCore.CAP.EntityFrameworkCore/SqlServerOptions.cs @@ -31,5 +31,7 @@ namespace DotNetCore.CAP.EntityFrameworkCore /// Default is . /// public string MigrationsHistoryTableName { get; set; } = DefaultMigrationsHistoryTableName; + + public Type DbContextType { get; set; } } } From 768a62c3a489a65988083ccac77cb02827ccf6d5 Mon Sep 17 00:00:00 2001 From: Savorboard Date: Sat, 15 Jul 2017 01:40:32 +0800 Subject: [PATCH 15/68] refactor --- samples/Sample.Kafka/AppDbContext.cs | 3 +- .../Controllers/ValuesController.cs | 13 +++-- samples/Sample.Kafka/Sample.Kafka.csproj | 1 - samples/Sample.Kafka/Startup.cs | 9 +-- .../CAP.BuilderExtensions.cs | 4 +- .../CAP.EFOptions.cs | 2 +- .../CapDbContext.cs | 5 +- .../CapPublisher.cs | 55 +++++++++++++++++++ .../EFStorageConnection.cs | 2 +- .../CAP.ServiceCollectionExtensions.cs | 4 +- src/DotNetCore.CAP/DotNetCore.CAP.csproj | 2 +- ...sage.Default.cs => IDispatcher.Default.cs} | 6 +- .../{IMessageProcessor.cs => IDispatcher.cs} | 2 +- .../Processor/IProcessingServer.Cap.cs | 11 ++-- .../Processor/IProcessor.PublishQueuer.cs | 2 +- .../Processor/IProcessor.SubscribeQueuer.cs | 2 +- 16 files changed, 93 insertions(+), 30 deletions(-) create mode 100644 src/DotNetCore.CAP.EntityFrameworkCore/CapPublisher.cs rename src/DotNetCore.CAP/Processor/{IProcessor.Message.Default.cs => IDispatcher.Default.cs} (94%) rename src/DotNetCore.CAP/Processor/{IMessageProcessor.cs => IDispatcher.cs} (74%) diff --git a/samples/Sample.Kafka/AppDbContext.cs b/samples/Sample.Kafka/AppDbContext.cs index 8140218..fe320e1 100644 --- a/samples/Sample.Kafka/AppDbContext.cs +++ b/samples/Sample.Kafka/AppDbContext.cs @@ -13,7 +13,8 @@ namespace Sample.Kafka { protected override void OnConfiguring(DbContextOptionsBuilder optionsBuilder) { - optionsBuilder.UseSqlServer("Server=192.168.2.206;Initial Catalog=Test;User Id=cmswuliu;Password=h7xY81agBn*Veiu3;MultipleActiveResultSets=True"); + //optionsBuilder.UseSqlServer("Server=192.168.2.206;Initial Catalog=Test;User Id=cmswuliu;Password=h7xY81agBn*Veiu3;MultipleActiveResultSets=True"); + optionsBuilder.UseSqlServer("Server=DESKTOP-M9R8T31;Initial Catalog=Test;User Id=sa;Password=P@ssw0rd;MultipleActiveResultSets=True"); } } } diff --git a/samples/Sample.Kafka/Controllers/ValuesController.cs b/samples/Sample.Kafka/Controllers/ValuesController.cs index ff42daf..6ed8a5c 100644 --- a/samples/Sample.Kafka/Controllers/ValuesController.cs +++ b/samples/Sample.Kafka/Controllers/ValuesController.cs @@ -1,9 +1,10 @@ using System; using System.Threading.Tasks; using DotNetCore.CAP; -using DotNetCore.CAP.Kafka; +using DotNetCore.CAP.RabbitMQ; using Microsoft.AspNetCore.Hosting; using Microsoft.AspNetCore.Mvc; +using Dapper; namespace Sample.Kafka.Controllers { @@ -11,10 +12,12 @@ namespace Sample.Kafka.Controllers public class ValuesController : Controller, ICapSubscribe { private readonly ICapPublisher _producer; + private readonly AppDbContext _dbContext ; - public ValuesController(ICapPublisher producer) + public ValuesController(ICapPublisher producer, AppDbContext dbContext) { _producer = producer; + _dbContext = dbContext; } [Route("/")] @@ -33,11 +36,11 @@ namespace Sample.Kafka.Controllers } [Route("~/send")] - public async Task SendTopic([FromServices] AppDbContext dbContext) + public async Task SendTopic() { - using (var trans = dbContext.Database.BeginTransaction()) + using (var trans = _dbContext.Database.BeginTransaction()) { - await _producer.PublishAsync("zzwl.topic.finace.callBack", new Person { Name = "Test", Age = 11 }); + await _producer.PublishAsync("zzwl.topic.finace.callBack",""); trans.Commit(); } diff --git a/samples/Sample.Kafka/Sample.Kafka.csproj b/samples/Sample.Kafka/Sample.Kafka.csproj index 506780b..3bb9d98 100644 --- a/samples/Sample.Kafka/Sample.Kafka.csproj +++ b/samples/Sample.Kafka/Sample.Kafka.csproj @@ -25,7 +25,6 @@ - diff --git a/samples/Sample.Kafka/Startup.cs b/samples/Sample.Kafka/Startup.cs index 8de4c57..715b5c5 100644 --- a/samples/Sample.Kafka/Startup.cs +++ b/samples/Sample.Kafka/Startup.cs @@ -28,13 +28,14 @@ namespace Sample.Kafka services.AddCap() .AddEntityFrameworkStores(x=> { - x.ConnectionString = "Server=192.168.2.206;Initial Catalog=Test;User Id=cmswuliu;Password=h7xY81agBn*Veiu3;MultipleActiveResultSets=True"; + //x.ConnectionString = "Server=192.168.2.206;Initial Catalog=Test;User Id=cmswuliu;Password=h7xY81agBn*Veiu3;MultipleActiveResultSets=True"; + x.ConnectionString = "Server=DESKTOP-M9R8T31;Initial Catalog=Test;User Id=sa;Password=P@ssw0rd;MultipleActiveResultSets=True"; }) .AddRabbitMQ(x => { - x.HostName = "192.168.2.206"; - x.UserName = "admin"; - x.Password = "123123"; + x.HostName = "localhost"; + // x.UserName = "admin"; + // x.Password = "123123"; }); //.AddKafka(x => x.Servers = ""); diff --git a/src/DotNetCore.CAP.EntityFrameworkCore/CAP.BuilderExtensions.cs b/src/DotNetCore.CAP.EntityFrameworkCore/CAP.BuilderExtensions.cs index c12ae54..fc6d53f 100644 --- a/src/DotNetCore.CAP.EntityFrameworkCore/CAP.BuilderExtensions.cs +++ b/src/DotNetCore.CAP.EntityFrameworkCore/CAP.BuilderExtensions.cs @@ -23,8 +23,10 @@ namespace Microsoft.Extensions.DependencyInjection builder.Services.AddSingleton(); builder.Services.AddScoped(); - builder.Services.AddTransient(); + builder.Services.AddScoped(); + builder.Services.AddTransient(); + builder.Services.Configure(actionOptions); var sqlServerOptions = new SqlServerOptions(); diff --git a/src/DotNetCore.CAP.EntityFrameworkCore/CAP.EFOptions.cs b/src/DotNetCore.CAP.EntityFrameworkCore/CAP.EFOptions.cs index df2240b..396d62e 100644 --- a/src/DotNetCore.CAP.EntityFrameworkCore/CAP.EFOptions.cs +++ b/src/DotNetCore.CAP.EntityFrameworkCore/CAP.EFOptions.cs @@ -12,7 +12,7 @@ namespace DotNetCore.CAP.EntityFrameworkCore public EFOptions() { - ConnectionString = "Server=DESKTOP-M9R8T31;Initial Catalog=WebApp1;User Id=sa;Password=P@ssw0rd;MultipleActiveResultSets=True"; + ConnectionString = "Server=DESKTOP-M9R8T31;Initial Catalog=Test;User Id=sa;Password=P@ssw0rd;MultipleActiveResultSets=True"; } /// diff --git a/src/DotNetCore.CAP.EntityFrameworkCore/CapDbContext.cs b/src/DotNetCore.CAP.EntityFrameworkCore/CapDbContext.cs index 882e742..0f06315 100644 --- a/src/DotNetCore.CAP.EntityFrameworkCore/CapDbContext.cs +++ b/src/DotNetCore.CAP.EntityFrameworkCore/CapDbContext.cs @@ -47,7 +47,7 @@ namespace DotNetCore.CAP.EntityFrameworkCore /// protected override void OnModelCreating(ModelBuilder modelBuilder) { - //_sqlServerOptions = new SqlServerOptions(); + _sqlServerOptions = new SqlServerOptions(); modelBuilder.HasDefaultSchema(_sqlServerOptions.Schema); modelBuilder.Entity(b => @@ -67,7 +67,8 @@ namespace DotNetCore.CAP.EntityFrameworkCore protected override void OnConfiguring(DbContextOptionsBuilder optionsBuilder) { - // optionsBuilder.UseSqlServer("Server=192.168.2.206;Initial Catalog=Test;User Id=cmswuliu;Password=h7xY81agBn*Veiu3;MultipleActiveResultSets=True"); + // optionsBuilder.UseSqlServer("Server=192.168.2.206;Initial Catalog=Test;User Id=cmswuliu;Password=h7xY81agBn*Veiu3;MultipleActiveResultSets=True"); + optionsBuilder.UseSqlServer("Server=DESKTOP-M9R8T31;Initial Catalog=Test;User Id=sa;Password=P@ssw0rd;MultipleActiveResultSets=True"); } } } \ No newline at end of file diff --git a/src/DotNetCore.CAP.EntityFrameworkCore/CapPublisher.cs b/src/DotNetCore.CAP.EntityFrameworkCore/CapPublisher.cs new file mode 100644 index 0000000..8aadb9d --- /dev/null +++ b/src/DotNetCore.CAP.EntityFrameworkCore/CapPublisher.cs @@ -0,0 +1,55 @@ +using System; +using System.Collections.Generic; +using System.Data; +using System.Text; +using System.Threading.Tasks; +using Dapper; +using DotNetCore.CAP.Infrastructure; +using DotNetCore.CAP.Models; +using DotNetCore.CAP.Processor; +using Microsoft.EntityFrameworkCore; +using Microsoft.EntityFrameworkCore.Infrastructure; +using Microsoft.EntityFrameworkCore.Storage; +using Microsoft.Extensions.DependencyInjection; + +namespace DotNetCore.CAP.EntityFrameworkCore +{ + public class CapPublisher : ICapPublisher + { + private readonly SqlServerOptions _options; + private readonly IServiceProvider _provider; + private readonly DbContext _dbContext; + + public CapPublisher(SqlServerOptions options, IServiceProvider provider) + { + _options = options; + _provider = provider; + _dbContext = (DbContext)_provider.GetService(_options.DbContextType); + } + + public async Task PublishAsync(string topic, string content) + { + var connection = _dbContext.Database.GetDbConnection(); + var transaction = _dbContext.Database.CurrentTransaction; + transaction = transaction ?? await _dbContext.Database.BeginTransactionAsync(IsolationLevel.ReadCommitted); + var dbTransaction = transaction.GetDbTransaction(); + + var message = new CapSentMessage + { + KeyName = topic, + Content = content, + StatusName = StatusName.Scheduled + }; + + var sql = "INSERT INTO [cap].[CapSentMessages] ([Id],[Added],[Content],[KeyName],[ExpiresAt],[Retries],[StatusName])VALUES(@Id,@Added,@Content,@KeyName,@ExpiresAt,@Retries,@StatusName)"; + await connection.ExecuteAsync(sql, message, transaction: dbTransaction); + + PublishQueuer.PulseEvent.Set(); + } + + public Task PublishAsync(string topic, T contentObj) + { + throw new NotImplementedException(); + } + } +} diff --git a/src/DotNetCore.CAP.EntityFrameworkCore/EFStorageConnection.cs b/src/DotNetCore.CAP.EntityFrameworkCore/EFStorageConnection.cs index b8e278e..8b38284 100644 --- a/src/DotNetCore.CAP.EntityFrameworkCore/EFStorageConnection.cs +++ b/src/DotNetCore.CAP.EntityFrameworkCore/EFStorageConnection.cs @@ -89,7 +89,7 @@ WHERE StatusName = '{StatusName.Scheduled}'"; var sql = $@" SELECT TOP (1) * FROM [{_options.Schema}].[{nameof(CapDbContext.CapReceivedMessages)}] WITH (readpast) -WHERE StateName = '{StatusName.Enqueued}'"; +WHERE StatusName = '{StatusName.Enqueued}'"; var connection = _context.GetDbConnection(); var message = (await connection.QueryAsync(sql)).FirstOrDefault(); diff --git a/src/DotNetCore.CAP/CAP.ServiceCollectionExtensions.cs b/src/DotNetCore.CAP/CAP.ServiceCollectionExtensions.cs index e38bd2b..dd993ea 100644 --- a/src/DotNetCore.CAP/CAP.ServiceCollectionExtensions.cs +++ b/src/DotNetCore.CAP/CAP.ServiceCollectionExtensions.cs @@ -55,14 +55,14 @@ namespace Microsoft.Extensions.DependencyInjection //Processors services.AddTransient(); services.AddTransient(); - services.AddTransient(); + services.AddTransient(); //Executors services.AddSingleton(); services.AddSingleton(); - services.TryAddScoped(); + // services.TryAddScoped(); return new CapBuilder(services); } diff --git a/src/DotNetCore.CAP/DotNetCore.CAP.csproj b/src/DotNetCore.CAP/DotNetCore.CAP.csproj index a59f6cd..5d73615 100644 --- a/src/DotNetCore.CAP/DotNetCore.CAP.csproj +++ b/src/DotNetCore.CAP/DotNetCore.CAP.csproj @@ -15,7 +15,7 @@ - + diff --git a/src/DotNetCore.CAP/Processor/IProcessor.Message.Default.cs b/src/DotNetCore.CAP/Processor/IDispatcher.Default.cs similarity index 94% rename from src/DotNetCore.CAP/Processor/IProcessor.Message.Default.cs rename to src/DotNetCore.CAP/Processor/IDispatcher.Default.cs index a9f6542..be0aa4f 100644 --- a/src/DotNetCore.CAP/Processor/IProcessor.Message.Default.cs +++ b/src/DotNetCore.CAP/Processor/IDispatcher.Default.cs @@ -8,7 +8,7 @@ using Microsoft.Extensions.Options; namespace DotNetCore.CAP.Processor { - public class DefaultMessageProcessor : IMessageProcessor + public class DefaultDispatcher : IDispatcher { private readonly IQueueExecutorFactory _queueExecutorFactory; private readonly IServiceProvider _provider; @@ -19,11 +19,11 @@ namespace DotNetCore.CAP.Processor internal static readonly AutoResetEvent PulseEvent = new AutoResetEvent(true); - public DefaultMessageProcessor( + public DefaultDispatcher( IServiceProvider provider, IQueueExecutorFactory queueExecutorFactory, IOptions capOptions, - ILogger logger) + ILogger logger) { _logger = logger; _queueExecutorFactory = queueExecutorFactory; diff --git a/src/DotNetCore.CAP/Processor/IMessageProcessor.cs b/src/DotNetCore.CAP/Processor/IDispatcher.cs similarity index 74% rename from src/DotNetCore.CAP/Processor/IMessageProcessor.cs rename to src/DotNetCore.CAP/Processor/IDispatcher.cs index e26b6fa..f358ac6 100644 --- a/src/DotNetCore.CAP/Processor/IMessageProcessor.cs +++ b/src/DotNetCore.CAP/Processor/IDispatcher.cs @@ -4,7 +4,7 @@ using System.Text; namespace DotNetCore.CAP.Processor { - public interface IMessageProcessor : IProcessor + public interface IDispatcher : IProcessor { bool Waiting { get; } } diff --git a/src/DotNetCore.CAP/Processor/IProcessingServer.Cap.cs b/src/DotNetCore.CAP/Processor/IProcessingServer.Cap.cs index d5bc699..8aae553 100644 --- a/src/DotNetCore.CAP/Processor/IProcessingServer.Cap.cs +++ b/src/DotNetCore.CAP/Processor/IProcessingServer.Cap.cs @@ -18,7 +18,7 @@ namespace DotNetCore.CAP.Processor private readonly CapOptions _options; private IProcessor[] _processors; - private IList _messageProcessors; + private IList _messageDispatchers; private ProcessingContext _context; private Task _compositeTask; private bool _disposed; @@ -34,6 +34,7 @@ namespace DotNetCore.CAP.Processor _provider = provider; _options = options.Value; _cts = new CancellationTokenSource(); + _messageDispatchers = new List(); } public void Start() @@ -90,7 +91,7 @@ namespace DotNetCore.CAP.Processor private bool AllProcessorsWaiting() { - foreach (var processor in _messageProcessors) + foreach (var processor in _messageDispatchers) { if (!processor.Waiting) { @@ -110,10 +111,10 @@ namespace DotNetCore.CAP.Processor var returnedProcessors = new List(); for (int i = 0; i < processorCount; i++) { - var messageProcessors = _provider.GetService(); - _messageProcessors.Add(messageProcessors); + var messageProcessors = _provider.GetService(); + _messageDispatchers.Add(messageProcessors); } - returnedProcessors.AddRange(_messageProcessors); + returnedProcessors.AddRange(_messageDispatchers); returnedProcessors.Add(_provider.GetService()); returnedProcessors.Add(_provider.GetService()); diff --git a/src/DotNetCore.CAP/Processor/IProcessor.PublishQueuer.cs b/src/DotNetCore.CAP/Processor/IProcessor.PublishQueuer.cs index cc9f644..9de598e 100644 --- a/src/DotNetCore.CAP/Processor/IProcessor.PublishQueuer.cs +++ b/src/DotNetCore.CAP/Processor/IProcessor.PublishQueuer.cs @@ -59,7 +59,7 @@ namespace DotNetCore.CAP.Processor context.ThrowIfStopping(); - DefaultMessageProcessor.PulseEvent.Set(); + DefaultDispatcher.PulseEvent.Set(); await WaitHandleEx.WaitAnyAsync(PulseEvent, context.CancellationToken.WaitHandle, _pollingDelay); diff --git a/src/DotNetCore.CAP/Processor/IProcessor.SubscribeQueuer.cs b/src/DotNetCore.CAP/Processor/IProcessor.SubscribeQueuer.cs index 7d1b7c2..17c2425 100644 --- a/src/DotNetCore.CAP/Processor/IProcessor.SubscribeQueuer.cs +++ b/src/DotNetCore.CAP/Processor/IProcessor.SubscribeQueuer.cs @@ -59,7 +59,7 @@ namespace DotNetCore.CAP.Processor context.ThrowIfStopping(); - DefaultMessageProcessor.PulseEvent.Set(); + DefaultDispatcher.PulseEvent.Set(); await WaitHandleEx.WaitAnyAsync(PulseEvent, context.CancellationToken.WaitHandle, _pollingDelay); From 27b74980a6e5ceb5beaa1d608626816e0e388e17 Mon Sep 17 00:00:00 2001 From: Savorboard Date: Sun, 16 Jul 2017 01:29:55 +0800 Subject: [PATCH 16/68] Modify the access level --- src/DotNetCore.CAP/Infrastructure/Helper.cs | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/src/DotNetCore.CAP/Infrastructure/Helper.cs b/src/DotNetCore.CAP/Infrastructure/Helper.cs index a6c8bb8..e254fed 100644 --- a/src/DotNetCore.CAP/Infrastructure/Helper.cs +++ b/src/DotNetCore.CAP/Infrastructure/Helper.cs @@ -4,7 +4,7 @@ using Newtonsoft.Json; namespace DotNetCore.CAP.Infrastructure { - internal static class Helper + public static class Helper { private static readonly DateTime Epoch = new DateTime(1970, 1, 1, 0, 0, 0, DateTimeKind.Utc); private static JsonSerializerSettings _serializerSettings; From 46154133cd51a595c0d7e9f711d0e14982dbfc87 Mon Sep 17 00:00:00 2001 From: Savorboard Date: Sun, 16 Jul 2017 01:30:55 +0800 Subject: [PATCH 17/68] Add the publish method with the transaction. --- .../CapPublisher.cs | 73 +++++++++++++++---- src/DotNetCore.CAP/ICapPublisher.cs | 32 +++++++- 2 files changed, 86 insertions(+), 19 deletions(-) diff --git a/src/DotNetCore.CAP.EntityFrameworkCore/CapPublisher.cs b/src/DotNetCore.CAP.EntityFrameworkCore/CapPublisher.cs index 8aadb9d..d91b53f 100644 --- a/src/DotNetCore.CAP.EntityFrameworkCore/CapPublisher.cs +++ b/src/DotNetCore.CAP.EntityFrameworkCore/CapPublisher.cs @@ -1,39 +1,85 @@ using System; -using System.Collections.Generic; using System.Data; -using System.Text; using System.Threading.Tasks; using Dapper; using DotNetCore.CAP.Infrastructure; using DotNetCore.CAP.Models; using DotNetCore.CAP.Processor; using Microsoft.EntityFrameworkCore; -using Microsoft.EntityFrameworkCore.Infrastructure; using Microsoft.EntityFrameworkCore.Storage; -using Microsoft.Extensions.DependencyInjection; namespace DotNetCore.CAP.EntityFrameworkCore { public class CapPublisher : ICapPublisher { private readonly SqlServerOptions _options; - private readonly IServiceProvider _provider; private readonly DbContext _dbContext; - public CapPublisher(SqlServerOptions options, IServiceProvider provider) + protected bool IsUsingEF { get; } + protected IServiceProvider ServiceProvider { get; } + + public CapPublisher(IServiceProvider provider, SqlServerOptions options) { + ServiceProvider = provider; _options = options; - _provider = provider; - _dbContext = (DbContext)_provider.GetService(_options.DbContextType); + + if (_options.DbContextType != null) + { + IsUsingEF = true; + _dbContext = (DbContext)ServiceProvider.GetService(_options.DbContextType); + } + } + + public Task PublishAsync(string topic, string content) + { + if (topic == null) throw new ArgumentNullException(nameof(topic)); + if (!IsUsingEF) throw new InvalidOperationException("If you are using the EntityFramework, you need to configure the DbContextType first." + + " otherwise you need to use overloaded method with IDbConnection and IDbTransaction."); + + return Publish(topic, content); + } + + public Task PublishAsync(string topic, T contentObj) + { + if (topic == null) throw new ArgumentNullException(nameof(topic)); + if (!IsUsingEF) throw new InvalidOperationException("If you are using the EntityFramework, you need to configure the DbContextType first." + + " otherwise you need to use overloaded method with IDbConnection and IDbTransaction."); + + var content = Helper.ToJson(contentObj); + return Publish(topic, content); + } + + public Task PublishAsync(string topic, string content, IDbConnection dbConnection) + { + if (IsUsingEF) throw new InvalidOperationException("If you are using the EntityFramework, you do not need to use this overloaded."); + if (topic == null) throw new ArgumentNullException(nameof(topic)); + if (dbConnection == null) throw new ArgumentNullException(nameof(dbConnection)); + + var dbTransaction = dbConnection.BeginTransaction(IsolationLevel.ReadCommitted); + return PublishWithTrans(topic, content, dbConnection, dbTransaction); + } + + public Task PublishAsync(string topic, string content, IDbConnection dbConnection, IDbTransaction dbTransaction) + { + if (IsUsingEF) throw new InvalidOperationException("If you are using the EntityFramework, you do not need to use this overloaded."); + if (topic == null) throw new ArgumentNullException(nameof(topic)); + if (dbConnection == null) throw new ArgumentNullException(nameof(dbConnection)); + if (dbTransaction == null) throw new ArgumentNullException(nameof(dbTransaction)); + + return PublishWithTrans(topic, content, dbConnection, dbTransaction); } - public async Task PublishAsync(string topic, string content) + private async Task Publish(string topic, string content) { var connection = _dbContext.Database.GetDbConnection(); var transaction = _dbContext.Database.CurrentTransaction; transaction = transaction ?? await _dbContext.Database.BeginTransactionAsync(IsolationLevel.ReadCommitted); var dbTransaction = transaction.GetDbTransaction(); + await PublishWithTrans(topic, content, connection, dbTransaction); + } + private async Task PublishWithTrans(string topic, string content, IDbConnection dbConnection, IDbTransaction dbTransaction) + { var message = new CapSentMessage { KeyName = topic, @@ -41,15 +87,10 @@ namespace DotNetCore.CAP.EntityFrameworkCore StatusName = StatusName.Scheduled }; - var sql = "INSERT INTO [cap].[CapSentMessages] ([Id],[Added],[Content],[KeyName],[ExpiresAt],[Retries],[StatusName])VALUES(@Id,@Added,@Content,@KeyName,@ExpiresAt,@Retries,@StatusName)"; - await connection.ExecuteAsync(sql, message, transaction: dbTransaction); + var sql = $"INSERT INTO {_options.Schema}.[{nameof(CapDbContext.CapSentMessages)}] ([Id],[Added],[Content],[KeyName],[ExpiresAt],[Retries],[StatusName])VALUES(@Id,@Added,@Content,@KeyName,@ExpiresAt,@Retries,@StatusName)"; + await dbConnection.ExecuteAsync(sql, message, transaction: dbTransaction); PublishQueuer.PulseEvent.Set(); } - - public Task PublishAsync(string topic, T contentObj) - { - throw new NotImplementedException(); - } } } diff --git a/src/DotNetCore.CAP/ICapPublisher.cs b/src/DotNetCore.CAP/ICapPublisher.cs index c1bcb99..aff0c5e 100644 --- a/src/DotNetCore.CAP/ICapPublisher.cs +++ b/src/DotNetCore.CAP/ICapPublisher.cs @@ -1,4 +1,6 @@ -using System.Threading.Tasks; +using System; +using System.Data; +using System.Threading.Tasks; namespace DotNetCore.CAP { @@ -9,18 +11,42 @@ namespace DotNetCore.CAP { /// /// Publish a string message to specified topic. + /// + /// If you are using the EntityFramework, you need to configure the DbContextType first. + /// otherwise you need to use overloaded method with IDbConnection and IDbTransaction. + /// /// /// the topic name or exchange router key. /// message body content. Task PublishAsync(string topic, string content); /// - /// Publis a object message to specified topic. + /// Publis a object message to specified topic. + /// + /// If you are using the EntityFramework, you need to configure the DbContextType first. + /// otherwise you need to use overloaded method with IDbConnection and IDbTransaction. + /// /// /// The type of conetent object. /// the topic name or exchange router key. /// object instance that will be serialized of json. - /// Task PublishAsync(string topic, T contentObj); + + /// + /// Publish a string message to specified topic with transacton. + /// + /// the topic name or exchange router key. + /// message body content. + /// the dbConnection of + Task PublishAsync(string topic, string content, IDbConnection dbConnection); + + /// + /// Publish a string message to specified topic with transacton. + /// + /// the topic name or exchange router key. + /// message body content. + /// the connection of + /// the transaction of + Task PublishAsync(string topic, string content, IDbConnection dbConnection, IDbTransaction dbTransaction); } } \ No newline at end of file From 7b5c328543a193a31afd6c25d8d76cd1bb23b63b Mon Sep 17 00:00:00 2001 From: Savorboard Date: Sun, 16 Jul 2017 01:31:23 +0800 Subject: [PATCH 18/68] Remove unused files. --- .../CapPublisherExtensions.cs | 49 ------------------- src/DotNetCore.CAP/DotNetCore.CAP.csproj | 8 +-- 2 files changed, 2 insertions(+), 55 deletions(-) delete mode 100644 src/DotNetCore.CAP.EntityFrameworkCore/CapPublisherExtensions.cs diff --git a/src/DotNetCore.CAP.EntityFrameworkCore/CapPublisherExtensions.cs b/src/DotNetCore.CAP.EntityFrameworkCore/CapPublisherExtensions.cs deleted file mode 100644 index 0d4a4b6..0000000 --- a/src/DotNetCore.CAP.EntityFrameworkCore/CapPublisherExtensions.cs +++ /dev/null @@ -1,49 +0,0 @@ -using System; -using System.Collections.Generic; -using System.Data; -using System.Threading.Tasks; -using DotNetCore.CAP.Models; -using Dapper; -using Microsoft.EntityFrameworkCore; -using Microsoft.EntityFrameworkCore.Infrastructure; -using DotNetCore.CAP.Infrastructure; -using DotNetCore.CAP.Processor; - -namespace DotNetCore.CAP -{ - static class CapPublisherExtensions - { - public static async Task Publish(this ICapPublisher publisher, string topic, string content, DatabaseFacade database) - { - var connection = database.GetDbConnection(); - var transaction = database.CurrentTransaction; - transaction = transaction ?? await database.BeginTransactionAsync(IsolationLevel.ReadCommitted); - - var message = new CapSentMessage - { - KeyName = topic, - Content = content, - StatusName = StatusName.Enqueued - }; - - var sql = "INSERT INTO [cap].[CapSentMessages] ([Id],[Added],[Content],[KeyName],[ExpiresAt],[Retries],[StatusName])VALUES(@Id,@Added,@Content,@KeyName,@ExpiresAt,@Retries,@StatusName)"; - await connection.ExecuteAsync(sql, transaction); - PublishQueuer.PulseEvent.Set(); - - } - - public static async Task Publish(this ICapPublisher publisher, string topic, string content, IDbConnection connection, IDbTransaction transaction) - { - var message = new CapSentMessage - { - KeyName = topic, - Content = content, - StatusName = StatusName.Enqueued - }; - - var sql = "INSERT INTO [cap].[CapSentMessages] ([Id],[Added],[Content],[KeyName],[ExpiresAt],[Retries],[StatusName])VALUES(@Id,@Added,@Content,@KeyName,@ExpiresAt,@Retries,@StatusName)"; - await connection.ExecuteAsync(sql, transaction); - PublishQueuer.PulseEvent.Set(); - } - } -} \ No newline at end of file diff --git a/src/DotNetCore.CAP/DotNetCore.CAP.csproj b/src/DotNetCore.CAP/DotNetCore.CAP.csproj index 5d73615..bc8227c 100644 --- a/src/DotNetCore.CAP/DotNetCore.CAP.csproj +++ b/src/DotNetCore.CAP/DotNetCore.CAP.csproj @@ -12,12 +12,7 @@ False - - - - - - + @@ -27,6 +22,7 @@ + From a6beba9781e6dc40930d08d918591c55b1f48aef Mon Sep 17 00:00:00 2001 From: Savorboard Date: Sun, 16 Jul 2017 02:58:57 +0800 Subject: [PATCH 19/68] update samples using new api. --- samples/Sample.Kafka/Startup.cs | 20 ++++++-------------- 1 file changed, 6 insertions(+), 14 deletions(-) diff --git a/samples/Sample.Kafka/Startup.cs b/samples/Sample.Kafka/Startup.cs index 715b5c5..6271903 100644 --- a/samples/Sample.Kafka/Startup.cs +++ b/samples/Sample.Kafka/Startup.cs @@ -1,5 +1,4 @@ -using DotNetCore.CAP.EntityFrameworkCore; -using Microsoft.AspNetCore.Builder; +using Microsoft.AspNetCore.Builder; using Microsoft.AspNetCore.Hosting; using Microsoft.Extensions.Configuration; using Microsoft.Extensions.DependencyInjection; @@ -26,18 +25,11 @@ namespace Sample.Kafka { services.AddDbContext(); - services.AddCap() - .AddEntityFrameworkStores(x=> { - //x.ConnectionString = "Server=192.168.2.206;Initial Catalog=Test;User Id=cmswuliu;Password=h7xY81agBn*Veiu3;MultipleActiveResultSets=True"; - x.ConnectionString = "Server=DESKTOP-M9R8T31;Initial Catalog=Test;User Id=sa;Password=P@ssw0rd;MultipleActiveResultSets=True"; - }) - .AddRabbitMQ(x => - { - x.HostName = "localhost"; - // x.UserName = "admin"; - // x.Password = "123123"; - }); - //.AddKafka(x => x.Servers = ""); + services.AddCap(x=> { + x.UseEntityFramework(); + x.UseSqlServer("Server=DESKTOP-M9R8T31;Initial Catalog=Test;User Id=sa;Password=P@ssw0rd;MultipleActiveResultSets=True"); + x.UseRabbitMQ("localhost"); + }); // Add framework services. services.AddMvc(); From 14aada21b78b31e28ef3813921a270e575b345c0 Mon Sep 17 00:00:00 2001 From: Savorboard Date: Sun, 16 Jul 2017 03:00:04 +0800 Subject: [PATCH 20/68] refactor options configuration moudle. --- .../CAP.BuilderExtensions.cs | 52 ----------------- .../CAP.EFOptions.cs | 35 +----------- .../CAP.Options.Extensions.cs | 47 ++++++++++++++++ .../CAP.SqlServerCapOptionsExtension.cs | 42 ++++++++++++++ .../CAP.SqlServerOptions.cs | 16 ++++++ .../SqlServerOptions.cs | 37 ------------ .../CAP.BuilderExtensions.cs | 31 ---------- .../CAP.KafkaCapOptionsExtension.cs | 28 ++++++++++ src/DotNetCore.CAP.Kafka/CAP.KafkaOptions.cs | 2 +- .../CAP.Options.Extensions.cs | 26 +++++++++ .../CAP.BuilderExtensions.cs | 22 -------- .../CAP.Options.Extensions.cs | 25 +++++++++ .../CAP.RabbiMQOptions.cs | 2 +- .../CAP.RabbitMQCapOptionsExtension.cs | 29 ++++++++++ src/DotNetCore.CAP/CAP.Options.cs | 16 +++++- .../CAP.ServiceCollectionExtensions.cs | 21 +++---- src/DotNetCore.CAP/ICapOptionsExtension.cs | 9 +++ src/DotNetCore.CAP/ICapPublisher.Default.cs | 56 ------------------- test/DotNetCore.CAP.Test/CAP.BuilderTest.cs | 29 +++++++--- .../ConsumerServiceSelectorTest.cs | 2 +- .../DotNetCore.CAP.Test.csproj | 9 +-- 21 files changed, 276 insertions(+), 260 deletions(-) delete mode 100644 src/DotNetCore.CAP.EntityFrameworkCore/CAP.BuilderExtensions.cs create mode 100644 src/DotNetCore.CAP.EntityFrameworkCore/CAP.Options.Extensions.cs create mode 100644 src/DotNetCore.CAP.EntityFrameworkCore/CAP.SqlServerCapOptionsExtension.cs create mode 100644 src/DotNetCore.CAP.EntityFrameworkCore/CAP.SqlServerOptions.cs delete mode 100644 src/DotNetCore.CAP.EntityFrameworkCore/SqlServerOptions.cs delete mode 100644 src/DotNetCore.CAP.Kafka/CAP.BuilderExtensions.cs create mode 100644 src/DotNetCore.CAP.Kafka/CAP.KafkaCapOptionsExtension.cs create mode 100644 src/DotNetCore.CAP.Kafka/CAP.Options.Extensions.cs delete mode 100644 src/DotNetCore.CAP.RabbitMQ/CAP.BuilderExtensions.cs create mode 100644 src/DotNetCore.CAP.RabbitMQ/CAP.Options.Extensions.cs create mode 100644 src/DotNetCore.CAP.RabbitMQ/CAP.RabbitMQCapOptionsExtension.cs create mode 100644 src/DotNetCore.CAP/ICapOptionsExtension.cs delete mode 100644 src/DotNetCore.CAP/ICapPublisher.Default.cs diff --git a/src/DotNetCore.CAP.EntityFrameworkCore/CAP.BuilderExtensions.cs b/src/DotNetCore.CAP.EntityFrameworkCore/CAP.BuilderExtensions.cs deleted file mode 100644 index fc6d53f..0000000 --- a/src/DotNetCore.CAP.EntityFrameworkCore/CAP.BuilderExtensions.cs +++ /dev/null @@ -1,52 +0,0 @@ -using System; -using DotNetCore.CAP; -using DotNetCore.CAP.EntityFrameworkCore; -using DotNetCore.CAP.Processor; -using Microsoft.EntityFrameworkCore; - -namespace Microsoft.Extensions.DependencyInjection -{ - /// - /// Contains extension methods to for adding entity framework stores. - /// - public static class CapEntityFrameworkBuilderExtensions - { - /// - /// Adds an Entity Framework implementation of message stores. - /// - public static CapBuilder AddEntityFrameworkStores(this CapBuilder builder, Action actionOptions) - where TContext : DbContext - { - - //builder.Services.AddScoped>(); - - builder.Services.AddSingleton(); - builder.Services.AddScoped(); - - builder.Services.AddScoped(); - - builder.Services.AddTransient(); - - builder.Services.Configure(actionOptions); - - var sqlServerOptions = new SqlServerOptions(); - sqlServerOptions.DbContextType = typeof(TContext); - actionOptions(sqlServerOptions); - builder.Services.AddSingleton(sqlServerOptions); - - builder.Services.AddDbContext(options => - { - options.UseSqlServer(sqlServerOptions.ConnectionString, sqlOpts => - { - sqlOpts.MigrationsHistoryTable( - sqlServerOptions.MigrationsHistoryTableName, - sqlServerOptions.MigrationsHistoryTableSchema ?? sqlServerOptions.Schema); - }); - }); - - return builder; - } - - - } -} \ No newline at end of file diff --git a/src/DotNetCore.CAP.EntityFrameworkCore/CAP.EFOptions.cs b/src/DotNetCore.CAP.EntityFrameworkCore/CAP.EFOptions.cs index 396d62e..78ce66b 100644 --- a/src/DotNetCore.CAP.EntityFrameworkCore/CAP.EFOptions.cs +++ b/src/DotNetCore.CAP.EntityFrameworkCore/CAP.EFOptions.cs @@ -2,24 +2,13 @@ using System.Collections.Generic; using System.Text; -namespace DotNetCore.CAP.EntityFrameworkCore +namespace DotNetCore.CAP { public class EFOptions { public const string DefaultSchema = "cap"; public const string DefaultMigrationsHistoryTableName = "__EFMigrationsHistory"; - - public EFOptions() - { - ConnectionString = "Server=DESKTOP-M9R8T31;Initial Catalog=Test;User Id=sa;Password=P@ssw0rd;MultipleActiveResultSets=True"; - } - - /// - /// Gets or sets the database's connection string that will be used to store database entities. - /// - public string ConnectionString { get; set; } - /// /// Gets or sets the schema to use when creating database objects. /// Default is . @@ -37,25 +26,7 @@ namespace DotNetCore.CAP.EntityFrameworkCore /// Default is . /// public string MigrationsHistoryTableName { get; set; } = DefaultMigrationsHistoryTableName; - } - - //public static class CapOptionsExtensions - //{ - // public static EFOptions UseSqlServer(this CapOptions options, string connectionString) - // { - // return options.UseSqlServer(opts => - // { - // opts.ConnectionString = connectionString; - // }); - // } - - // public static EFOptions UseSqlServer(this CapOptions options, Action configure) - // { - // if (configure == null) throw new ArgumentNullException(nameof(configure)); - // (new EFOptions(configure)); - - // return options; - // } - //} + public Type DbContextType { get; internal set; } + } } diff --git a/src/DotNetCore.CAP.EntityFrameworkCore/CAP.Options.Extensions.cs b/src/DotNetCore.CAP.EntityFrameworkCore/CAP.Options.Extensions.cs new file mode 100644 index 0000000..bca946f --- /dev/null +++ b/src/DotNetCore.CAP.EntityFrameworkCore/CAP.Options.Extensions.cs @@ -0,0 +1,47 @@ +using System; +using DotNetCore.CAP; +using Microsoft.EntityFrameworkCore; + +namespace Microsoft.Extensions.DependencyInjection +{ + public static class CapOptionsExtensions + { + public static CapOptions UseSqlServer(this CapOptions options, string connectionString) + { + return options.UseSqlServer(opt => + { + opt.ConnectionString = connectionString; + }); + } + + public static CapOptions UseSqlServer(this CapOptions options, Action configure) + { + if (configure == null) throw new ArgumentNullException(nameof(configure)); + + options.RegisterExtension(new SqlServerCapOptionsExtension(configure)); + + return options; + } + + public static CapOptions UseEntityFramework(this CapOptions options) + where TContext : DbContext + { + return options.UseEntityFramework(opt => + { + opt.DbContextType = typeof(TContext); + }); + } + + public static CapOptions UseEntityFramework(this CapOptions options, Action configure) + where TContext : DbContext + { + if (configure == null) throw new ArgumentNullException(nameof(configure)); + + var efOptions = new EFOptions { DbContextType = typeof(TContext) }; + configure(efOptions); + options.RegisterExtension(new SqlServerCapOptionsExtension(configure)); + + return options; + } + } +} diff --git a/src/DotNetCore.CAP.EntityFrameworkCore/CAP.SqlServerCapOptionsExtension.cs b/src/DotNetCore.CAP.EntityFrameworkCore/CAP.SqlServerCapOptionsExtension.cs new file mode 100644 index 0000000..f750980 --- /dev/null +++ b/src/DotNetCore.CAP.EntityFrameworkCore/CAP.SqlServerCapOptionsExtension.cs @@ -0,0 +1,42 @@ +using System; +using Microsoft.EntityFrameworkCore; +using DotNetCore.CAP.EntityFrameworkCore; +using DotNetCore.CAP.Processor; +using Microsoft.Extensions.DependencyInjection; + +namespace DotNetCore.CAP +{ + public class SqlServerCapOptionsExtension : ICapOptionsExtension + { + private Action _configure; + + public SqlServerCapOptionsExtension(Action configure) + { + _configure = configure; + } + + public void AddServices(IServiceCollection services) + { + services.AddSingleton(); + services.AddScoped(); + services.AddScoped(); + services.AddTransient(); + + services.Configure(_configure); + + var sqlServerOptions = new SqlServerOptions(); + _configure(sqlServerOptions); + services.AddSingleton(sqlServerOptions); + + services.AddDbContext(options => + { + options.UseSqlServer(sqlServerOptions.ConnectionString, sqlOpts => + { + sqlOpts.MigrationsHistoryTable( + sqlServerOptions.MigrationsHistoryTableName, + sqlServerOptions.MigrationsHistoryTableSchema ?? sqlServerOptions.Schema); + }); + }); + } + } +} diff --git a/src/DotNetCore.CAP.EntityFrameworkCore/CAP.SqlServerOptions.cs b/src/DotNetCore.CAP.EntityFrameworkCore/CAP.SqlServerOptions.cs new file mode 100644 index 0000000..817e045 --- /dev/null +++ b/src/DotNetCore.CAP.EntityFrameworkCore/CAP.SqlServerOptions.cs @@ -0,0 +1,16 @@ +using System; +using System.Collections.Generic; +using System.Text; +using DotNetCore.CAP.EntityFrameworkCore; + +namespace DotNetCore.CAP +{ + public class SqlServerOptions : EFOptions + { + /// + /// Gets or sets the database's connection string that will be used to store database entities. + /// + public string ConnectionString { get; set; } //= "Server=DESKTOP-M9R8T31;Initial Catalog=Test;User Id=sa;Password=P@ssw0rd;MultipleActiveResultSets=True"; + + } +} diff --git a/src/DotNetCore.CAP.EntityFrameworkCore/SqlServerOptions.cs b/src/DotNetCore.CAP.EntityFrameworkCore/SqlServerOptions.cs deleted file mode 100644 index 03aebd3..0000000 --- a/src/DotNetCore.CAP.EntityFrameworkCore/SqlServerOptions.cs +++ /dev/null @@ -1,37 +0,0 @@ -using System; -using System.Collections.Generic; -using System.Text; - -namespace DotNetCore.CAP.EntityFrameworkCore -{ - public class SqlServerOptions - { - public const string DefaultSchema = "cap"; - public const string DefaultMigrationsHistoryTableName = "__EFMigrationsHistory"; - - /// - /// Gets or sets the database's connection string that will be used to store database entities. - /// - public string ConnectionString { get; set; } - - /// - /// Gets or sets the schema to use when creating database objects. - /// Default is . - /// - public string Schema { get; set; } = DefaultSchema; - - /// - /// Gets or sets the migrations history table's schema. - /// If this is null, will be used. - /// - public string MigrationsHistoryTableSchema { get; set; } - - /// - /// Gets or sets the migrations history table's name. - /// Default is . - /// - public string MigrationsHistoryTableName { get; set; } = DefaultMigrationsHistoryTableName; - - public Type DbContextType { get; set; } - } -} diff --git a/src/DotNetCore.CAP.Kafka/CAP.BuilderExtensions.cs b/src/DotNetCore.CAP.Kafka/CAP.BuilderExtensions.cs deleted file mode 100644 index 4f064b4..0000000 --- a/src/DotNetCore.CAP.Kafka/CAP.BuilderExtensions.cs +++ /dev/null @@ -1,31 +0,0 @@ -using System; -using DotNetCore.CAP; -using DotNetCore.CAP.Kafka; - -namespace Microsoft.Extensions.DependencyInjection -{ - /// - /// Contains extension methods to for adding kafka service. - /// - public static class CapBuilderExtensions - { - /// - /// Adds an Kafka implementation of CAP messages queue. - /// - /// The instance this method extends - /// An action to configure the . - /// An for creating and configuring the CAP system. - public static CapBuilder AddKafka(this CapBuilder builder, Action setupAction) - { - if (setupAction == null) throw new ArgumentNullException(nameof(setupAction)); - - builder.Services.Configure(setupAction); - - builder.Services.AddSingleton(); - - builder.Services.AddTransient(); - - return builder; - } - } -} \ No newline at end of file diff --git a/src/DotNetCore.CAP.Kafka/CAP.KafkaCapOptionsExtension.cs b/src/DotNetCore.CAP.Kafka/CAP.KafkaCapOptionsExtension.cs new file mode 100644 index 0000000..2a6466c --- /dev/null +++ b/src/DotNetCore.CAP.Kafka/CAP.KafkaCapOptionsExtension.cs @@ -0,0 +1,28 @@ +using System; +using DotNetCore.CAP.Kafka; +using Microsoft.Extensions.DependencyInjection; + +namespace DotNetCore.CAP +{ + public class KafkaCapOptionsExtension : ICapOptionsExtension + { + private Action _configure; + + public KafkaCapOptionsExtension(Action configure) + { + _configure = configure; + } + + public void AddServices(IServiceCollection services) + { + services.Configure(_configure); + + var kafkaOptions = new KafkaOptions(); + _configure(kafkaOptions); + services.AddSingleton(kafkaOptions); + + services.AddSingleton(); + services.AddTransient(); + } + } +} diff --git a/src/DotNetCore.CAP.Kafka/CAP.KafkaOptions.cs b/src/DotNetCore.CAP.Kafka/CAP.KafkaOptions.cs index b7836b6..1c09b77 100644 --- a/src/DotNetCore.CAP.Kafka/CAP.KafkaOptions.cs +++ b/src/DotNetCore.CAP.Kafka/CAP.KafkaOptions.cs @@ -2,7 +2,7 @@ using System.Collections.Generic; using System.Linq; -namespace DotNetCore.CAP.Kafka +namespace DotNetCore.CAP { /// /// Provides programmatic configuration for the CAP kafka project. diff --git a/src/DotNetCore.CAP.Kafka/CAP.Options.Extensions.cs b/src/DotNetCore.CAP.Kafka/CAP.Options.Extensions.cs new file mode 100644 index 0000000..8afeece --- /dev/null +++ b/src/DotNetCore.CAP.Kafka/CAP.Options.Extensions.cs @@ -0,0 +1,26 @@ +using System; +using DotNetCore.CAP; +using DotNetCore.CAP.Kafka; + +namespace Microsoft.Extensions.DependencyInjection +{ + public static class CapOptionsExtensions + { + public static CapOptions UseKafka(this CapOptions options, string bootstrapServers) + { + return options.UseRabbitMQ(opt => + { + opt.Servers = bootstrapServers; + }); + } + + public static CapOptions UseRabbitMQ(this CapOptions options, Action configure) + { + if (configure == null) throw new ArgumentNullException(nameof(configure)); + + options.RegisterExtension(new KafkaCapOptionsExtension(configure)); + + return options; + } + } +} \ No newline at end of file diff --git a/src/DotNetCore.CAP.RabbitMQ/CAP.BuilderExtensions.cs b/src/DotNetCore.CAP.RabbitMQ/CAP.BuilderExtensions.cs deleted file mode 100644 index 2a92956..0000000 --- a/src/DotNetCore.CAP.RabbitMQ/CAP.BuilderExtensions.cs +++ /dev/null @@ -1,22 +0,0 @@ -using System; -using DotNetCore.CAP; -using DotNetCore.CAP.RabbitMQ; - -namespace Microsoft.Extensions.DependencyInjection -{ - public static class CapBuilderExtensions - { - public static CapBuilder AddRabbitMQ(this CapBuilder builder, Action setupOptions) - { - if (setupOptions == null) throw new ArgumentNullException(nameof(setupOptions)); - - builder.Services.Configure(setupOptions); - - builder.Services.AddSingleton(); - - builder.Services.AddTransient(); - - return builder; - } - } -} \ No newline at end of file diff --git a/src/DotNetCore.CAP.RabbitMQ/CAP.Options.Extensions.cs b/src/DotNetCore.CAP.RabbitMQ/CAP.Options.Extensions.cs new file mode 100644 index 0000000..9320be4 --- /dev/null +++ b/src/DotNetCore.CAP.RabbitMQ/CAP.Options.Extensions.cs @@ -0,0 +1,25 @@ +using System; +using DotNetCore.CAP; + +namespace Microsoft.Extensions.DependencyInjection +{ + public static class CapOptionsExtensions + { + public static CapOptions UseRabbitMQ(this CapOptions options, string hostName) + { + return options.UseRabbitMQ(opt => + { + opt.HostName = hostName; + }); + } + + public static CapOptions UseRabbitMQ(this CapOptions options, Action configure) + { + if (configure == null) throw new ArgumentNullException(nameof(configure)); + + options.RegisterExtension(new RabbitMQCapOptionsExtension(configure)); + + return options; + } + } +} \ No newline at end of file diff --git a/src/DotNetCore.CAP.RabbitMQ/CAP.RabbiMQOptions.cs b/src/DotNetCore.CAP.RabbitMQ/CAP.RabbiMQOptions.cs index 9dcc030..de82129 100644 --- a/src/DotNetCore.CAP.RabbitMQ/CAP.RabbiMQOptions.cs +++ b/src/DotNetCore.CAP.RabbitMQ/CAP.RabbiMQOptions.cs @@ -1,4 +1,4 @@ -namespace DotNetCore.CAP.RabbitMQ +namespace DotNetCore.CAP { public class RabbitMQOptions { diff --git a/src/DotNetCore.CAP.RabbitMQ/CAP.RabbitMQCapOptionsExtension.cs b/src/DotNetCore.CAP.RabbitMQ/CAP.RabbitMQCapOptionsExtension.cs new file mode 100644 index 0000000..17f7faa --- /dev/null +++ b/src/DotNetCore.CAP.RabbitMQ/CAP.RabbitMQCapOptionsExtension.cs @@ -0,0 +1,29 @@ +using System; +using DotNetCore.CAP.RabbitMQ; +using Microsoft.Extensions.DependencyInjection; + +namespace DotNetCore.CAP +{ + public class RabbitMQCapOptionsExtension : ICapOptionsExtension + { + private Action _configure; + + public RabbitMQCapOptionsExtension(Action configure) + { + _configure = configure; + } + + public void AddServices(IServiceCollection services) + { + services.Configure(_configure); + + var rabbitMQOptions = new RabbitMQOptions(); + _configure(rabbitMQOptions); + + services.AddSingleton(rabbitMQOptions); + + services.AddSingleton(); + services.AddTransient(); + } + } +} diff --git a/src/DotNetCore.CAP/CAP.Options.cs b/src/DotNetCore.CAP/CAP.Options.cs index 1b18152..003f6c0 100644 --- a/src/DotNetCore.CAP/CAP.Options.cs +++ b/src/DotNetCore.CAP/CAP.Options.cs @@ -1,10 +1,14 @@ -namespace DotNetCore.CAP +using System; + +namespace DotNetCore.CAP { /// /// Represents all the options you can use to configure the system. /// public class CapOptions { + internal ICapOptionsExtension Extension { get; private set; } + /// /// Default value for polling delay timeout, in seconds. /// @@ -30,5 +34,15 @@ /// Productor job polling delay time. Default is 8 sec. /// public int PollingDelay { get; set; } = 8; + + + /// + /// Registers an extension that will be executed when building services. + /// + /// + public void RegisterExtension(ICapOptionsExtension extension) + { + Extension = extension ?? throw new ArgumentNullException(nameof(extension)); + } } } \ No newline at end of file diff --git a/src/DotNetCore.CAP/CAP.ServiceCollectionExtensions.cs b/src/DotNetCore.CAP/CAP.ServiceCollectionExtensions.cs index dd993ea..f6fda76 100644 --- a/src/DotNetCore.CAP/CAP.ServiceCollectionExtensions.cs +++ b/src/DotNetCore.CAP/CAP.ServiceCollectionExtensions.cs @@ -17,16 +17,6 @@ namespace Microsoft.Extensions.DependencyInjection /// public static class ServiceCollectionExtensions { - /// - /// Adds and configures the CAP services for the consitence. - /// - /// The services available in the application. - /// An for application services. - public static CapBuilder AddCap(this IServiceCollection services) - { - return services.AddCap(x => new CapOptions()); - } - /// /// Adds and configures the consistence services for the consitence. /// @@ -37,6 +27,8 @@ namespace Microsoft.Extensions.DependencyInjection this IServiceCollection services, Action setupAction) { + if (setupAction == null) throw new ArgumentNullException(nameof(setupAction)); + services.TryAddSingleton(); services.Configure(setupAction); @@ -60,9 +52,12 @@ namespace Microsoft.Extensions.DependencyInjection //Executors services.AddSingleton(); services.AddSingleton(); - - - // services.TryAddScoped(); + + //Options + var options = new CapOptions(); + setupAction(options); + options.Extension?.AddServices(services); + services.AddSingleton(options); return new CapBuilder(services); } diff --git a/src/DotNetCore.CAP/ICapOptionsExtension.cs b/src/DotNetCore.CAP/ICapOptionsExtension.cs new file mode 100644 index 0000000..5e29f50 --- /dev/null +++ b/src/DotNetCore.CAP/ICapOptionsExtension.cs @@ -0,0 +1,9 @@ +using Microsoft.Extensions.DependencyInjection; + +namespace DotNetCore.CAP +{ + public interface ICapOptionsExtension + { + void AddServices(IServiceCollection services); + } +} diff --git a/src/DotNetCore.CAP/ICapPublisher.Default.cs b/src/DotNetCore.CAP/ICapPublisher.Default.cs deleted file mode 100644 index 5dc0b59..0000000 --- a/src/DotNetCore.CAP/ICapPublisher.Default.cs +++ /dev/null @@ -1,56 +0,0 @@ -using System; -using System.Threading.Tasks; -using DotNetCore.CAP.Infrastructure; -using DotNetCore.CAP.Models; -using Microsoft.Extensions.Logging; - -namespace DotNetCore.CAP -{ - /// - /// Cap default implement. - /// - public class DefaultCapPublisher : ICapPublisher - { - private readonly ILogger _logger; - - public DefaultCapPublisher( ILogger logger) - { - _logger = logger; - } - - public Task PublishAsync(string topic, string content) - { - if (topic == null) throw new ArgumentNullException(nameof(topic)); - if (content == null) throw new ArgumentNullException(nameof(content)); - - return StoreMessage(topic, content); - } - - public Task PublishAsync(string topic, T contentObj) - { - if (topic == null) throw new ArgumentNullException(nameof(topic)); - - var content = Helper.ToJson(contentObj); - if (content == null) - throw new InvalidCastException(nameof(contentObj)); - - return StoreMessage(topic, content); - } - - private async Task StoreMessage(string topic, string content) - { - var message = new CapSentMessage - { - KeyName = topic, - Content = content, - StatusName = StatusName.Enqueued - }; - - //await _store.StoreSentMessageAsync(message); - - // WaitHandleEx.PulseEvent.Set(); - - // _logger.EnqueuingSentMessage(topic, content); - } - } -} \ No newline at end of file diff --git a/test/DotNetCore.CAP.Test/CAP.BuilderTest.cs b/test/DotNetCore.CAP.Test/CAP.BuilderTest.cs index 6289ee2..282b36d 100644 --- a/test/DotNetCore.CAP.Test/CAP.BuilderTest.cs +++ b/test/DotNetCore.CAP.Test/CAP.BuilderTest.cs @@ -5,6 +5,7 @@ using DotNetCore.CAP.Processor; using DotNetCore.CAP.Models; using Microsoft.Extensions.DependencyInjection; using Xunit; +using System.Data; namespace DotNetCore.CAP.Test { @@ -34,17 +35,17 @@ namespace DotNetCore.CAP.Test // Assert.NotNull(thingy); //} - [Fact] - public void CanOverrideProducerService() - { - var services = new ServiceCollection(); - services.AddCap().AddProducerService(); + //[Fact] + //public void CanOverrideProducerService() + //{ + // var services = new ServiceCollection(); + // services.AddCap(x=> { }); - var thingy = services.BuildServiceProvider() - .GetRequiredService() as MyProducerService; + // var thingy = services.BuildServiceProvider() + // .GetRequiredService() as MyProducerService; - Assert.NotNull(thingy); - } + // Assert.NotNull(thingy); + //} private class MyProducerService : ICapPublisher @@ -58,6 +59,16 @@ namespace DotNetCore.CAP.Test { throw new NotImplementedException(); } + + public Task PublishAsync(string topic, string content, IDbConnection dbConnection) + { + throw new NotImplementedException(); + } + + public Task PublishAsync(string topic, string content, IDbConnection dbConnection, IDbTransaction dbTransaction) + { + throw new NotImplementedException(); + } } } } \ No newline at end of file diff --git a/test/DotNetCore.CAP.Test/ConsumerServiceSelectorTest.cs b/test/DotNetCore.CAP.Test/ConsumerServiceSelectorTest.cs index da670c9..1fc5ca8 100644 --- a/test/DotNetCore.CAP.Test/ConsumerServiceSelectorTest.cs +++ b/test/DotNetCore.CAP.Test/ConsumerServiceSelectorTest.cs @@ -20,7 +20,7 @@ namespace DotNetCore.CAP.Test services.AddScoped(); services.AddScoped(); services.AddLogging(); - services.AddCap(); + services.AddCap(x=> { }); _provider = services.BuildServiceProvider(); } diff --git a/test/DotNetCore.CAP.Test/DotNetCore.CAP.Test.csproj b/test/DotNetCore.CAP.Test/DotNetCore.CAP.Test.csproj index 47cebe2..81b5e2d 100644 --- a/test/DotNetCore.CAP.Test/DotNetCore.CAP.Test.csproj +++ b/test/DotNetCore.CAP.Test/DotNetCore.CAP.Test.csproj @@ -14,12 +14,9 @@ - - - - + @@ -28,6 +25,10 @@ + + + + From 847a9ecbce255e3d2b9552ae20d669febad6ef98 Mon Sep 17 00:00:00 2001 From: Savorboard Date: Sun, 16 Jul 2017 18:29:08 +0800 Subject: [PATCH 21/68] rename cap attribute routekey --- src/DotNetCore.CAP.Kafka/CapSubscribeAttribute.cs | 12 ++++++------ src/DotNetCore.CAP.Kafka/KafkaConsumerClient.cs | 2 +- src/DotNetCore.CAP.RabbitMQ/CapSubscribeAttribute.cs | 2 +- .../RabbitMQConsumerClient.cs | 2 +- src/DotNetCore.CAP/Abstractions/TopicAttribute.cs | 4 ++-- 5 files changed, 11 insertions(+), 11 deletions(-) diff --git a/src/DotNetCore.CAP.Kafka/CapSubscribeAttribute.cs b/src/DotNetCore.CAP.Kafka/CapSubscribeAttribute.cs index 3d906d1..92b2a93 100644 --- a/src/DotNetCore.CAP.Kafka/CapSubscribeAttribute.cs +++ b/src/DotNetCore.CAP.Kafka/CapSubscribeAttribute.cs @@ -4,24 +4,24 @@ namespace DotNetCore.CAP.Kafka { public class CapSubscribeAttribute : TopicAttribute { - public CapSubscribeAttribute(string topicName) - : this(topicName, 0) + public CapSubscribeAttribute(string name) + : this(name, 0) { } /// /// Not support /// - public CapSubscribeAttribute(string topicName, int partition) - : this(topicName, partition, 0) + public CapSubscribeAttribute(string name, int partition) + : this(name, partition, 0) { } /// /// Not support /// - public CapSubscribeAttribute(string topicName, int partition, long offset) - : base(topicName) + public CapSubscribeAttribute(string name, int partition, long offset) + : base(name) { Offset = offset; Partition = partition; diff --git a/src/DotNetCore.CAP.Kafka/KafkaConsumerClient.cs b/src/DotNetCore.CAP.Kafka/KafkaConsumerClient.cs index 52b34e3..ad79353 100644 --- a/src/DotNetCore.CAP.Kafka/KafkaConsumerClient.cs +++ b/src/DotNetCore.CAP.Kafka/KafkaConsumerClient.cs @@ -73,7 +73,7 @@ namespace DotNetCore.CAP.Kafka var message = new MessageContext { Group = _groupId, - KeyName = e.Topic, + Name = e.Topic, Content = e.Value }; MessageReceieved?.Invoke(sender, message); diff --git a/src/DotNetCore.CAP.RabbitMQ/CapSubscribeAttribute.cs b/src/DotNetCore.CAP.RabbitMQ/CapSubscribeAttribute.cs index 5e33a1c..cfbbc8d 100644 --- a/src/DotNetCore.CAP.RabbitMQ/CapSubscribeAttribute.cs +++ b/src/DotNetCore.CAP.RabbitMQ/CapSubscribeAttribute.cs @@ -4,7 +4,7 @@ namespace DotNetCore.CAP.RabbitMQ { public class CapSubscribeAttribute : TopicAttribute { - public CapSubscribeAttribute(string routingKey) : base(routingKey) + public CapSubscribeAttribute(string name) : base(name) { } diff --git a/src/DotNetCore.CAP.RabbitMQ/RabbitMQConsumerClient.cs b/src/DotNetCore.CAP.RabbitMQ/RabbitMQConsumerClient.cs index c32e6df..35bbcc0 100644 --- a/src/DotNetCore.CAP.RabbitMQ/RabbitMQConsumerClient.cs +++ b/src/DotNetCore.CAP.RabbitMQ/RabbitMQConsumerClient.cs @@ -87,7 +87,7 @@ namespace DotNetCore.CAP.RabbitMQ var message = new MessageContext { Group = _queueName, - KeyName = e.RoutingKey, + Name = e.RoutingKey, Content = Encoding.UTF8.GetString(e.Body) }; MessageReceieved?.Invoke(sender, message); diff --git a/src/DotNetCore.CAP/Abstractions/TopicAttribute.cs b/src/DotNetCore.CAP/Abstractions/TopicAttribute.cs index 1e1ef2d..bc4bb8f 100644 --- a/src/DotNetCore.CAP/Abstractions/TopicAttribute.cs +++ b/src/DotNetCore.CAP/Abstractions/TopicAttribute.cs @@ -8,9 +8,9 @@ namespace DotNetCore.CAP.Abstractions [AttributeUsage(AttributeTargets.Method | AttributeTargets.Class, AllowMultiple = true)] public abstract class TopicAttribute : Attribute { - protected TopicAttribute(string topicName) + protected TopicAttribute(string name) { - Name = topicName; + Name = name; } /// From 8294a58671a70e0c0cb2e6dd9343de2f2e6558e6 Mon Sep 17 00:00:00 2001 From: Savorboard Date: Sun, 16 Jul 2017 18:30:47 +0800 Subject: [PATCH 22/68] rename sentmessage to publishedmessage. --- .../IQueueExecutor.Publish.Base.cs | 16 ++++++---------- src/DotNetCore.CAP/IStorageConnection.cs | 14 ++++++-------- src/DotNetCore.CAP/IStorageTransaction.cs | 4 ++-- ...{CapSentMessage.cs => CapPublishedMessage.cs} | 15 +++++++-------- .../Processor/States/IState.Enqueued.cs | 2 +- .../Processor/States/IState.Failed.cs | 2 +- .../Processor/States/IState.Processing.cs | 2 +- .../Processor/States/IState.Scheduled.cs | 2 +- .../Processor/States/IState.Succeeded.cs | 2 +- src/DotNetCore.CAP/Processor/States/IState.cs | 2 +- .../Processor/States/IStateChanger.Default.cs | 2 +- .../Processor/States/IStateChanger.Extensions.cs | 2 +- .../Processor/States/IStateChanger.cs | 2 +- 13 files changed, 30 insertions(+), 37 deletions(-) rename src/DotNetCore.CAP/Models/{CapSentMessage.cs => CapPublishedMessage.cs} (63%) diff --git a/src/DotNetCore.CAP/IQueueExecutor.Publish.Base.cs b/src/DotNetCore.CAP/IQueueExecutor.Publish.Base.cs index 09f7d40..074fd66 100644 --- a/src/DotNetCore.CAP/IQueueExecutor.Publish.Base.cs +++ b/src/DotNetCore.CAP/IQueueExecutor.Publish.Base.cs @@ -1,11 +1,9 @@ using System; -using System.Collections.Generic; using System.Diagnostics; -using System.Text; using System.Threading.Tasks; +using DotNetCore.CAP.Models; using DotNetCore.CAP.Processor; using DotNetCore.CAP.Processor.States; -using DotNetCore.CAP.Models; using Microsoft.Extensions.Logging; namespace DotNetCore.CAP @@ -28,8 +26,7 @@ namespace DotNetCore.CAP { using (fetched) { - - var message = await connection.GetSentMessageAsync(fetched.MessageId); + var message = await connection.GetPublishedMessageAsync(fetched.MessageId); try { var sp = Stopwatch.StartNew(); @@ -39,7 +36,7 @@ namespace DotNetCore.CAP { _logger.JobRetrying(message.Retries); } - var result = await PublishAsync(message.KeyName, message.Content); + var result = await PublishAsync(message.Name, message.Content); sp.Stop(); var newState = default(IState); @@ -72,16 +69,15 @@ namespace DotNetCore.CAP return OperateResult.Success; } - catch (Exception ex) { - _logger.ExceptionOccuredWhileExecutingJob(message?.KeyName, ex); + _logger.ExceptionOccuredWhileExecutingJob(message?.Name, ex); return OperateResult.Failed(ex); } } } - private async Task UpdateJobForRetryAsync(CapSentMessage message, IStorageConnection connection) + private async Task UpdateJobForRetryAsync(CapPublishedMessage message, IStorageConnection connection) { var retryBehavior = RetryBehavior.DefaultRetry; @@ -102,4 +98,4 @@ namespace DotNetCore.CAP return true; } } -} +} \ No newline at end of file diff --git a/src/DotNetCore.CAP/IStorageConnection.cs b/src/DotNetCore.CAP/IStorageConnection.cs index da3b799..4c16a5f 100644 --- a/src/DotNetCore.CAP/IStorageConnection.cs +++ b/src/DotNetCore.CAP/IStorageConnection.cs @@ -9,14 +9,13 @@ namespace DotNetCore.CAP /// public interface IStorageConnection : IDisposable { - - //Sent messages + //Sent messages /// /// Returns the message with the given id. /// /// The message's id. - Task GetSentMessageAsync(string id); + Task GetPublishedMessageAsync(int id); /// /// Fetches the next message to be executed. @@ -26,7 +25,7 @@ namespace DotNetCore.CAP /// /// Returns the next message to be enqueued. /// - Task GetNextSentMessageToBeEnqueuedAsync(); + Task GetNextPublishedMessageToBeEnqueuedAsync(); // Received messages @@ -40,14 +39,13 @@ namespace DotNetCore.CAP /// Returns the message with the given id. /// /// The message's id. - Task GetReceivedMessageAsync(string id); - + Task GetReceivedMessageAsync(int id); /// /// Returns the next message to be enqueued. /// Task GetNextReceviedMessageToBeEnqueuedAsync(); - + //----------------------------------------- /// @@ -55,4 +53,4 @@ namespace DotNetCore.CAP /// IStorageTransaction CreateTransaction(); } -} +} \ No newline at end of file diff --git a/src/DotNetCore.CAP/IStorageTransaction.cs b/src/DotNetCore.CAP/IStorageTransaction.cs index 7aaf6e1..642cc4d 100644 --- a/src/DotNetCore.CAP/IStorageTransaction.cs +++ b/src/DotNetCore.CAP/IStorageTransaction.cs @@ -6,11 +6,11 @@ namespace DotNetCore.CAP { public interface IStorageTransaction : IDisposable { - void UpdateMessage(CapSentMessage message); + void UpdateMessage(CapPublishedMessage message); void UpdateMessage(CapReceivedMessage message); - void EnqueueMessage(CapSentMessage message); + void EnqueueMessage(CapPublishedMessage message); void EnqueueMessage(CapReceivedMessage message); diff --git a/src/DotNetCore.CAP/Models/CapSentMessage.cs b/src/DotNetCore.CAP/Models/CapPublishedMessage.cs similarity index 63% rename from src/DotNetCore.CAP/Models/CapSentMessage.cs rename to src/DotNetCore.CAP/Models/CapPublishedMessage.cs index 6752536..7780a09 100644 --- a/src/DotNetCore.CAP/Models/CapSentMessage.cs +++ b/src/DotNetCore.CAP/Models/CapPublishedMessage.cs @@ -3,29 +3,28 @@ using DotNetCore.CAP.Infrastructure; namespace DotNetCore.CAP.Models { - public class CapSentMessage + public class CapPublishedMessage { /// - /// Initializes a new instance of . + /// Initializes a new instance of . /// /// /// The Id property is initialized to from a new GUID string value. /// - public CapSentMessage() + public CapPublishedMessage() { - Id = Guid.NewGuid().ToString(); Added = DateTime.Now; } - public CapSentMessage(MessageContext message) + public CapPublishedMessage(MessageContext message) { - KeyName = message.KeyName; + Name = message.Name; Content = message.Content; } - public string Id { get; set; } + public int Id { get; set; } - public string KeyName { get; set; } + public string Name { get; set; } public string Content { get; set; } diff --git a/src/DotNetCore.CAP/Processor/States/IState.Enqueued.cs b/src/DotNetCore.CAP/Processor/States/IState.Enqueued.cs index 41d83ae..ca53699 100644 --- a/src/DotNetCore.CAP/Processor/States/IState.Enqueued.cs +++ b/src/DotNetCore.CAP/Processor/States/IState.Enqueued.cs @@ -11,7 +11,7 @@ namespace DotNetCore.CAP.Processor.States public string Name => StateName; - public void Apply(CapSentMessage message, IStorageTransaction transaction) + public void Apply(CapPublishedMessage message, IStorageTransaction transaction) { transaction.EnqueueMessage(message); } diff --git a/src/DotNetCore.CAP/Processor/States/IState.Failed.cs b/src/DotNetCore.CAP/Processor/States/IState.Failed.cs index 9bbfbd6..49fda9b 100644 --- a/src/DotNetCore.CAP/Processor/States/IState.Failed.cs +++ b/src/DotNetCore.CAP/Processor/States/IState.Failed.cs @@ -11,7 +11,7 @@ namespace DotNetCore.CAP.Processor.States public string Name => StateName; - public void Apply(CapSentMessage message, IStorageTransaction transaction) + public void Apply(CapPublishedMessage message, IStorageTransaction transaction) { } diff --git a/src/DotNetCore.CAP/Processor/States/IState.Processing.cs b/src/DotNetCore.CAP/Processor/States/IState.Processing.cs index db66b86..9827e76 100644 --- a/src/DotNetCore.CAP/Processor/States/IState.Processing.cs +++ b/src/DotNetCore.CAP/Processor/States/IState.Processing.cs @@ -11,7 +11,7 @@ namespace DotNetCore.CAP.Processor.States public string Name => StateName; - public void Apply(CapSentMessage message, IStorageTransaction transaction) + public void Apply(CapPublishedMessage message, IStorageTransaction transaction) { } diff --git a/src/DotNetCore.CAP/Processor/States/IState.Scheduled.cs b/src/DotNetCore.CAP/Processor/States/IState.Scheduled.cs index 6113f3b..49f0c95 100644 --- a/src/DotNetCore.CAP/Processor/States/IState.Scheduled.cs +++ b/src/DotNetCore.CAP/Processor/States/IState.Scheduled.cs @@ -11,7 +11,7 @@ namespace DotNetCore.CAP.Processor.States public string Name => StateName; - public void Apply(CapSentMessage message, IStorageTransaction transaction) + public void Apply(CapPublishedMessage message, IStorageTransaction transaction) { } diff --git a/src/DotNetCore.CAP/Processor/States/IState.Succeeded.cs b/src/DotNetCore.CAP/Processor/States/IState.Succeeded.cs index b3b4f4d..294591c 100644 --- a/src/DotNetCore.CAP/Processor/States/IState.Succeeded.cs +++ b/src/DotNetCore.CAP/Processor/States/IState.Succeeded.cs @@ -11,7 +11,7 @@ namespace DotNetCore.CAP.Processor.States public string Name => StateName; - public void Apply(CapSentMessage message, IStorageTransaction transaction) + public void Apply(CapPublishedMessage message, IStorageTransaction transaction) { } diff --git a/src/DotNetCore.CAP/Processor/States/IState.cs b/src/DotNetCore.CAP/Processor/States/IState.cs index 0416fe9..c43fc74 100644 --- a/src/DotNetCore.CAP/Processor/States/IState.cs +++ b/src/DotNetCore.CAP/Processor/States/IState.cs @@ -9,7 +9,7 @@ namespace DotNetCore.CAP.Processor.States string Name { get; } - void Apply(CapSentMessage message, IStorageTransaction transaction); + void Apply(CapPublishedMessage message, IStorageTransaction transaction); void Apply(CapReceivedMessage message, IStorageTransaction transaction); } diff --git a/src/DotNetCore.CAP/Processor/States/IStateChanger.Default.cs b/src/DotNetCore.CAP/Processor/States/IStateChanger.Default.cs index 1e4c99b..b8b419b 100644 --- a/src/DotNetCore.CAP/Processor/States/IStateChanger.Default.cs +++ b/src/DotNetCore.CAP/Processor/States/IStateChanger.Default.cs @@ -4,7 +4,7 @@ namespace DotNetCore.CAP.Processor.States { public class StateChanger : IStateChanger { - public void ChangeState(CapSentMessage message, IState state, IStorageTransaction transaction) + public void ChangeState(CapPublishedMessage message, IState state, IStorageTransaction transaction) { //var now = DateTime.UtcNow; //if (state.ExpiresAfter != null) diff --git a/src/DotNetCore.CAP/Processor/States/IStateChanger.Extensions.cs b/src/DotNetCore.CAP/Processor/States/IStateChanger.Extensions.cs index 5ccc018..6bd1d12 100644 --- a/src/DotNetCore.CAP/Processor/States/IStateChanger.Extensions.cs +++ b/src/DotNetCore.CAP/Processor/States/IStateChanger.Extensions.cs @@ -6,7 +6,7 @@ namespace DotNetCore.CAP.Processor.States public static class StateChangerExtensions { public static async Task ChangeStateAsync( - this IStateChanger @this, CapSentMessage message, IState state, IStorageConnection connection) + this IStateChanger @this, CapPublishedMessage message, IState state, IStorageConnection connection) { using (var transaction = connection.CreateTransaction()) { diff --git a/src/DotNetCore.CAP/Processor/States/IStateChanger.cs b/src/DotNetCore.CAP/Processor/States/IStateChanger.cs index 1cba968..949ea31 100644 --- a/src/DotNetCore.CAP/Processor/States/IStateChanger.cs +++ b/src/DotNetCore.CAP/Processor/States/IStateChanger.cs @@ -4,7 +4,7 @@ namespace DotNetCore.CAP.Processor.States { public interface IStateChanger { - void ChangeState(CapSentMessage message, IState state, IStorageTransaction transaction); + void ChangeState(CapPublishedMessage message, IState state, IStorageTransaction transaction); void ChangeState(CapReceivedMessage message, IState state, IStorageTransaction transaction); } From 14a3d4a57c8036666af545ef0070170a1f9df110 Mon Sep 17 00:00:00 2001 From: Savorboard Date: Sun, 16 Jul 2017 18:31:14 +0800 Subject: [PATCH 23/68] temporarily remove --- .../DatabaseTestHost.cs | 98 ++--- .../EFMessageStoreTest.cs | 339 +++++++++--------- .../20170708050416_InitDB.Designer.cs | 69 ---- .../Migrations/20170708050416_InitDB.cs | 56 --- .../Migrations/TestDbContextModelSnapshot.cs | 68 ---- .../TestDbContext.cs | 13 - .../TestHost.cs | 2 +- 7 files changed, 216 insertions(+), 429 deletions(-) delete mode 100644 test/DotNetCore.CAP.EntityFrameworkCore.Test/Migrations/20170708050416_InitDB.Designer.cs delete mode 100644 test/DotNetCore.CAP.EntityFrameworkCore.Test/Migrations/20170708050416_InitDB.cs delete mode 100644 test/DotNetCore.CAP.EntityFrameworkCore.Test/Migrations/TestDbContextModelSnapshot.cs delete mode 100644 test/DotNetCore.CAP.EntityFrameworkCore.Test/TestDbContext.cs diff --git a/test/DotNetCore.CAP.EntityFrameworkCore.Test/DatabaseTestHost.cs b/test/DotNetCore.CAP.EntityFrameworkCore.Test/DatabaseTestHost.cs index 993e685..d6b21b6 100644 --- a/test/DotNetCore.CAP.EntityFrameworkCore.Test/DatabaseTestHost.cs +++ b/test/DotNetCore.CAP.EntityFrameworkCore.Test/DatabaseTestHost.cs @@ -5,58 +5,58 @@ using Microsoft.EntityFrameworkCore; namespace DotNetCore.CAP.EntityFrameworkCore.Test { - public abstract class DatabaseTestHost : TestHost - { - private static bool _sqlObjectInstalled; + //public abstract class DatabaseTestHost : TestHost + //{ + // private static bool _sqlObjectInstalled; - protected override void PostBuildServices() - { - base.PostBuildServices(); - InitializeDatabase(); - } + // protected override void PostBuildServices() + // { + // base.PostBuildServices(); + // InitializeDatabase(); + // } - public override void Dispose() - { - DeleteAllData(); - base.Dispose(); - } + // public override void Dispose() + // { + // DeleteAllData(); + // base.Dispose(); + // } - private void InitializeDatabase() - { - if (!_sqlObjectInstalled) - { - using (CreateScope()) - { - var context = GetService(); - context.Database.EnsureDeleted(); - context.Database.Migrate(); - _sqlObjectInstalled = true; - } - } - } + // private void InitializeDatabase() + // { + // if (!_sqlObjectInstalled) + // { + // using (CreateScope()) + // { + // var context = GetService(); + // context.Database.EnsureDeleted(); + // context.Database.Migrate(); + // _sqlObjectInstalled = true; + // } + // } + // } - private void DeleteAllData() - { - using (CreateScope()) - { - var context = GetService(); + // private void DeleteAllData() + // { + // using (CreateScope()) + // { + // var context = GetService(); - var commands = new[] - { - "DISABLE TRIGGER ALL ON ?", - "ALTER TABLE ? NOCHECK CONSTRAINT ALL", - "DELETE FROM ?", - "ALTER TABLE ? CHECK CONSTRAINT ALL", - "ENABLE TRIGGER ALL ON ?" - }; - foreach (var command in commands) - { - context.Database.GetDbConnection().Execute( - "sp_MSforeachtable", - new {command1 = command}, - commandType: CommandType.StoredProcedure); - } - } - } - } + // var commands = new[] + // { + // "DISABLE TRIGGER ALL ON ?", + // "ALTER TABLE ? NOCHECK CONSTRAINT ALL", + // "DELETE FROM ?", + // "ALTER TABLE ? CHECK CONSTRAINT ALL", + // "ENABLE TRIGGER ALL ON ?" + // }; + // foreach (var command in commands) + // { + // context.Database.GetDbConnection().Execute( + // "sp_MSforeachtable", + // new {command1 = command}, + // commandType: CommandType.StoredProcedure); + // } + // } + // } + //} } \ No newline at end of file diff --git a/test/DotNetCore.CAP.EntityFrameworkCore.Test/EFMessageStoreTest.cs b/test/DotNetCore.CAP.EntityFrameworkCore.Test/EFMessageStoreTest.cs index 2897482..e59f393 100644 --- a/test/DotNetCore.CAP.EntityFrameworkCore.Test/EFMessageStoreTest.cs +++ b/test/DotNetCore.CAP.EntityFrameworkCore.Test/EFMessageStoreTest.cs @@ -1,175 +1,168 @@ -using System; -using System.Linq; -using DotNetCore.CAP.Infrastructure; -using DotNetCore.CAP.Models; -using Microsoft.Extensions.DependencyInjection; -using Xunit; - -namespace DotNetCore.CAP.EntityFrameworkCore.Test +namespace DotNetCore.CAP.EntityFrameworkCore.Test { - public class EFMessageStoreTest : DatabaseTestHost - { - [Fact] - public void CanCreateSentMessageUsingEF() - { - using (var db = CreateContext()) - { - var guid = Guid.NewGuid().ToString(); - var message = new CapSentMessage - { - Id = guid, - Content = "this is message body", - StatusName = StatusName.Enqueued - }; - db.Attach(message).State = Microsoft.EntityFrameworkCore.EntityState.Added; - - db.SaveChanges(); - - Assert.True(db.CapSentMessages.Any(u => u.Id == guid)); - Assert.NotNull(db.CapSentMessages.FirstOrDefault(u => u.StatusName == StatusName.Enqueued)); - } - } - - [Fact] - public void CanUpdateSentMessageUsingEF() - { - using (var db = CreateContext()) - { - var guid = Guid.NewGuid().ToString(); - var message = new CapSentMessage - { - Id = guid, - Content = "this is message body", - StatusName = StatusName.Enqueued - }; - db.Attach(message).State = Microsoft.EntityFrameworkCore.EntityState.Added; - - db.SaveChanges(); - - var selectedMessage = db.CapSentMessages.FirstOrDefault(u => u.StatusName == StatusName.Enqueued); - Assert.NotNull(selectedMessage); - - selectedMessage.StatusName = StatusName.Succeeded; - selectedMessage.Content = "Test"; - db.SaveChanges(); - - selectedMessage = db.CapSentMessages.FirstOrDefault(u => u.StatusName == StatusName.Succeeded); - Assert.NotNull(selectedMessage); - Assert.True(selectedMessage.Content == "Test"); - } - } - - [Fact] - public void CanRemoveSentMessageUsingEF() - { - using (var db = CreateContext()) - { - var guid = Guid.NewGuid().ToString(); - var message = new CapSentMessage - { - Id = guid, - Content = "this is message body", - StatusName = StatusName.Enqueued - }; - db.Attach(message).State = Microsoft.EntityFrameworkCore.EntityState.Added; - - db.SaveChanges(); - - var selectedMessage = db.CapSentMessages.FirstOrDefault(u => u.StatusName == StatusName.Enqueued); - Assert.NotNull(selectedMessage); - - db.CapSentMessages.Remove(selectedMessage); - db.SaveChanges(); - selectedMessage = db.CapSentMessages.FirstOrDefault(u => u.StatusName == StatusName.Enqueued); - Assert.Null(selectedMessage); - } - } - - [Fact] - public void CanCreateReceivedMessageUsingEF() - { - using (var db = CreateContext()) - { - var guid = Guid.NewGuid().ToString(); - var message = new CapReceivedMessage - { - Id = guid, - Content = "this is message body", - StatusName = StatusName.Enqueued - }; - db.Attach(message).State = Microsoft.EntityFrameworkCore.EntityState.Added; - - db.SaveChanges(); - - Assert.True(db.CapReceivedMessages.Any(u => u.Id == guid)); - Assert.NotNull(db.CapReceivedMessages.FirstOrDefault(u => u.StatusName == StatusName.Enqueued)); - } - } - - [Fact] - public void CanUpdateReceivedMessageUsingEF() - { - using (var db = CreateContext()) - { - var guid = Guid.NewGuid().ToString(); - var message = new CapReceivedMessage - { - Id = guid, - Content = "this is message body", - StatusName = StatusName.Enqueued - }; - db.Attach(message).State = Microsoft.EntityFrameworkCore.EntityState.Added; - - db.SaveChanges(); - - var selectedMessage = db.CapReceivedMessages.FirstOrDefault(u => u.StatusName == StatusName.Enqueued); - Assert.NotNull(selectedMessage); - - selectedMessage.StatusName = StatusName.Succeeded; - selectedMessage.Content = "Test"; - db.SaveChanges(); - - selectedMessage = db.CapReceivedMessages.FirstOrDefault(u => u.StatusName == StatusName.Succeeded); - Assert.NotNull(selectedMessage); - Assert.True(selectedMessage.Content == "Test"); - } - } - - [Fact] - public void CanRemoveReceivedMessageUsingEF() - { - using (var db = CreateContext()) - { - var guid = Guid.NewGuid().ToString(); - var message = new CapReceivedMessage - { - Id = guid, - Content = "this is message body", - StatusName = StatusName.Enqueued - }; - db.Attach(message).State = Microsoft.EntityFrameworkCore.EntityState.Added; - - db.SaveChanges(); - - var selectedMessage = db.CapReceivedMessages.FirstOrDefault(u => u.StatusName == StatusName.Enqueued); - Assert.NotNull(selectedMessage); - - db.CapReceivedMessages.Remove(selectedMessage); - db.SaveChanges(); - selectedMessage = db.CapReceivedMessages.FirstOrDefault(u => u.StatusName == StatusName.Enqueued); - Assert.Null(selectedMessage); - } - } - - public TestDbContext CreateContext(bool delete = false) - { - var db = Provider.GetRequiredService(); - if (delete) - { - db.Database.EnsureDeleted(); - } - db.Database.EnsureCreated(); - return db; - } - } + //public class EFMessageStoreTest : DatabaseTestHost + //{ + // [Fact] + // public void CanCreateSentMessageUsingEF() + // { + // using (var db = CreateContext()) + // { + // var guid = Guid.NewGuid().ToString(); + // var message = new CapPublishedMessage + // { + // Id = guid, + // Content = "this is message body", + // StatusName = StatusName.Enqueued + // }; + // db.Attach(message).State = Microsoft.EntityFrameworkCore.EntityState.Added; + + // db.SaveChanges(); + + // Assert.True(db.CapSentMessages.Any(u => u.Id == guid)); + // Assert.NotNull(db.CapSentMessages.FirstOrDefault(u => u.StatusName == StatusName.Enqueued)); + // } + // } + + // [Fact] + // public void CanUpdateSentMessageUsingEF() + // { + // using (var db = CreateContext()) + // { + // var guid = Guid.NewGuid().ToString(); + // var message = new CapPublishedMessage + // { + // Id = guid, + // Content = "this is message body", + // StatusName = StatusName.Enqueued + // }; + // db.Attach(message).State = Microsoft.EntityFrameworkCore.EntityState.Added; + + // db.SaveChanges(); + + // var selectedMessage = db.CapSentMessages.FirstOrDefault(u => u.StatusName == StatusName.Enqueued); + // Assert.NotNull(selectedMessage); + + // selectedMessage.StatusName = StatusName.Succeeded; + // selectedMessage.Content = "Test"; + // db.SaveChanges(); + + // selectedMessage = db.CapSentMessages.FirstOrDefault(u => u.StatusName == StatusName.Succeeded); + // Assert.NotNull(selectedMessage); + // Assert.True(selectedMessage.Content == "Test"); + // } + // } + + // [Fact] + // public void CanRemoveSentMessageUsingEF() + // { + // using (var db = CreateContext()) + // { + // var guid = Guid.NewGuid().ToString(); + // var message = new CapPublishedMessage + // { + // Id = guid, + // Content = "this is message body", + // StatusName = StatusName.Enqueued + // }; + // db.Attach(message).State = Microsoft.EntityFrameworkCore.EntityState.Added; + + // db.SaveChanges(); + + // var selectedMessage = db.CapSentMessages.FirstOrDefault(u => u.StatusName == StatusName.Enqueued); + // Assert.NotNull(selectedMessage); + + // db.CapSentMessages.Remove(selectedMessage); + // db.SaveChanges(); + // selectedMessage = db.CapSentMessages.FirstOrDefault(u => u.StatusName == StatusName.Enqueued); + // Assert.Null(selectedMessage); + // } + // } + + // [Fact] + // public void CanCreateReceivedMessageUsingEF() + // { + // using (var db = CreateContext()) + // { + // var guid = Guid.NewGuid().ToString(); + // var message = new CapReceivedMessage + // { + // Id = guid, + // Content = "this is message body", + // StatusName = StatusName.Enqueued + // }; + // db.Attach(message).State = Microsoft.EntityFrameworkCore.EntityState.Added; + + // db.SaveChanges(); + + // Assert.True(db.CapReceivedMessages.Any(u => u.Id == guid)); + // Assert.NotNull(db.CapReceivedMessages.FirstOrDefault(u => u.StatusName == StatusName.Enqueued)); + // } + // } + + // [Fact] + // public void CanUpdateReceivedMessageUsingEF() + // { + // using (var db = CreateContext()) + // { + // var guid = Guid.NewGuid().ToString(); + // var message = new CapReceivedMessage + // { + // Id = guid, + // Content = "this is message body", + // StatusName = StatusName.Enqueued + // }; + // db.Attach(message).State = Microsoft.EntityFrameworkCore.EntityState.Added; + + // db.SaveChanges(); + + // var selectedMessage = db.CapReceivedMessages.FirstOrDefault(u => u.StatusName == StatusName.Enqueued); + // Assert.NotNull(selectedMessage); + + // selectedMessage.StatusName = StatusName.Succeeded; + // selectedMessage.Content = "Test"; + // db.SaveChanges(); + + // selectedMessage = db.CapReceivedMessages.FirstOrDefault(u => u.StatusName == StatusName.Succeeded); + // Assert.NotNull(selectedMessage); + // Assert.True(selectedMessage.Content == "Test"); + // } + // } + + // [Fact] + // public void CanRemoveReceivedMessageUsingEF() + // { + // using (var db = CreateContext()) + // { + // var guid = Guid.NewGuid().ToString(); + // var message = new CapReceivedMessage + // { + // Id = guid, + // Content = "this is message body", + // StatusName = StatusName.Enqueued + // }; + // db.Attach(message).State = Microsoft.EntityFrameworkCore.EntityState.Added; + + // db.SaveChanges(); + + // var selectedMessage = db.CapReceivedMessages.FirstOrDefault(u => u.StatusName == StatusName.Enqueued); + // Assert.NotNull(selectedMessage); + + // db.CapReceivedMessages.Remove(selectedMessage); + // db.SaveChanges(); + // selectedMessage = db.CapReceivedMessages.FirstOrDefault(u => u.StatusName == StatusName.Enqueued); + // Assert.Null(selectedMessage); + // } + // } + + // public TestDbContext CreateContext(bool delete = false) + // { + // var db = Provider.GetRequiredService(); + // if (delete) + // { + // db.Database.EnsureDeleted(); + // } + // db.Database.EnsureCreated(); + // return db; + // } + //} } \ No newline at end of file diff --git a/test/DotNetCore.CAP.EntityFrameworkCore.Test/Migrations/20170708050416_InitDB.Designer.cs b/test/DotNetCore.CAP.EntityFrameworkCore.Test/Migrations/20170708050416_InitDB.Designer.cs deleted file mode 100644 index a018f8f..0000000 --- a/test/DotNetCore.CAP.EntityFrameworkCore.Test/Migrations/20170708050416_InitDB.Designer.cs +++ /dev/null @@ -1,69 +0,0 @@ -using System; -using Microsoft.EntityFrameworkCore; -using Microsoft.EntityFrameworkCore.Infrastructure; -using Microsoft.EntityFrameworkCore.Metadata; -using Microsoft.EntityFrameworkCore.Migrations; -using DotNetCore.CAP.EntityFrameworkCore.Test; - -namespace DotNetCore.CAP.EntityFrameworkCore.Test.Migrations -{ - [DbContext(typeof(TestDbContext))] - [Migration("20170708050416_InitDB")] - partial class InitDB - { - protected override void BuildTargetModel(ModelBuilder modelBuilder) - { - modelBuilder - .HasAnnotation("ProductVersion", "1.1.2") - .HasAnnotation("SqlServer:ValueGenerationStrategy", SqlServerValueGenerationStrategy.IdentityColumn); - - modelBuilder.Entity("DotNetCore.CAP.Infrastructure.CapReceivedMessage", b => - { - b.Property("Id") - .ValueGeneratedOnAdd(); - - b.Property("Added"); - - b.Property("Content"); - - b.Property("Group"); - - b.Property("KeyName"); - - b.Property("LastRun"); - - b.Property("Retries"); - - b.Property("StatusName") - .HasMaxLength(50); - - b.HasKey("Id"); - - b.ToTable("CapReceivedMessages"); - }); - - modelBuilder.Entity("DotNetCore.CAP.Infrastructure.CapSentMessage", b => - { - b.Property("Id") - .ValueGeneratedOnAdd(); - - b.Property("Added"); - - b.Property("Content"); - - b.Property("KeyName"); - - b.Property("LastRun"); - - b.Property("Retries"); - - b.Property("StatusName") - .HasMaxLength(50); - - b.HasKey("Id"); - - b.ToTable("CapSentMessages"); - }); - } - } -} diff --git a/test/DotNetCore.CAP.EntityFrameworkCore.Test/Migrations/20170708050416_InitDB.cs b/test/DotNetCore.CAP.EntityFrameworkCore.Test/Migrations/20170708050416_InitDB.cs deleted file mode 100644 index af02548..0000000 --- a/test/DotNetCore.CAP.EntityFrameworkCore.Test/Migrations/20170708050416_InitDB.cs +++ /dev/null @@ -1,56 +0,0 @@ -using System; -using System.Collections.Generic; -using Microsoft.EntityFrameworkCore.Migrations; - -namespace DotNetCore.CAP.EntityFrameworkCore.Test.Migrations -{ - public partial class InitDB : Migration - { - protected override void Up(MigrationBuilder migrationBuilder) - { - migrationBuilder.CreateTable( - name: "CapReceivedMessages", - columns: table => new - { - Id = table.Column(nullable: false), - Added = table.Column(nullable: false), - Content = table.Column(nullable: true), - Group = table.Column(nullable: true), - KeyName = table.Column(nullable: true), - LastRun = table.Column(nullable: false), - Retries = table.Column(nullable: false), - StatusName = table.Column(maxLength: 50, nullable: true) - }, - constraints: table => - { - table.PrimaryKey("PK_CapReceivedMessages", x => x.Id); - }); - - migrationBuilder.CreateTable( - name: "CapSentMessages", - columns: table => new - { - Id = table.Column(nullable: false), - Added = table.Column(nullable: false), - Content = table.Column(nullable: true), - KeyName = table.Column(nullable: true), - LastRun = table.Column(nullable: false), - Retries = table.Column(nullable: false), - StatusName = table.Column(maxLength: 50, nullable: true) - }, - constraints: table => - { - table.PrimaryKey("PK_CapSentMessages", x => x.Id); - }); - } - - protected override void Down(MigrationBuilder migrationBuilder) - { - migrationBuilder.DropTable( - name: "CapReceivedMessages"); - - migrationBuilder.DropTable( - name: "CapSentMessages"); - } - } -} diff --git a/test/DotNetCore.CAP.EntityFrameworkCore.Test/Migrations/TestDbContextModelSnapshot.cs b/test/DotNetCore.CAP.EntityFrameworkCore.Test/Migrations/TestDbContextModelSnapshot.cs deleted file mode 100644 index a4e6e0a..0000000 --- a/test/DotNetCore.CAP.EntityFrameworkCore.Test/Migrations/TestDbContextModelSnapshot.cs +++ /dev/null @@ -1,68 +0,0 @@ -using System; -using Microsoft.EntityFrameworkCore; -using Microsoft.EntityFrameworkCore.Infrastructure; -using Microsoft.EntityFrameworkCore.Metadata; -using Microsoft.EntityFrameworkCore.Migrations; -using DotNetCore.CAP.EntityFrameworkCore.Test; - -namespace DotNetCore.CAP.EntityFrameworkCore.Test.Migrations -{ - [DbContext(typeof(TestDbContext))] - partial class TestDbContextModelSnapshot : ModelSnapshot - { - protected override void BuildModel(ModelBuilder modelBuilder) - { - modelBuilder - .HasAnnotation("ProductVersion", "1.1.2") - .HasAnnotation("SqlServer:ValueGenerationStrategy", SqlServerValueGenerationStrategy.IdentityColumn); - - modelBuilder.Entity("DotNetCore.CAP.Infrastructure.CapReceivedMessage", b => - { - b.Property("Id") - .ValueGeneratedOnAdd(); - - b.Property("Added"); - - b.Property("Content"); - - b.Property("Group"); - - b.Property("KeyName"); - - b.Property("LastRun"); - - b.Property("Retries"); - - b.Property("StatusName") - .HasMaxLength(50); - - b.HasKey("Id"); - - b.ToTable("CapReceivedMessages"); - }); - - modelBuilder.Entity("DotNetCore.CAP.Infrastructure.CapSentMessage", b => - { - b.Property("Id") - .ValueGeneratedOnAdd(); - - b.Property("Added"); - - b.Property("Content"); - - b.Property("KeyName"); - - b.Property("LastRun"); - - b.Property("Retries"); - - b.Property("StatusName") - .HasMaxLength(50); - - b.HasKey("Id"); - - b.ToTable("CapSentMessages"); - }); - } - } -} diff --git a/test/DotNetCore.CAP.EntityFrameworkCore.Test/TestDbContext.cs b/test/DotNetCore.CAP.EntityFrameworkCore.Test/TestDbContext.cs deleted file mode 100644 index 4b7cbef..0000000 --- a/test/DotNetCore.CAP.EntityFrameworkCore.Test/TestDbContext.cs +++ /dev/null @@ -1,13 +0,0 @@ -using Microsoft.EntityFrameworkCore; - -namespace DotNetCore.CAP.EntityFrameworkCore.Test -{ - public class TestDbContext : CapDbContext - { - protected override void OnConfiguring(DbContextOptionsBuilder optionsBuilder) - { - var connectionString = ConnectionUtil.GetConnectionString(); - optionsBuilder.UseSqlServer(connectionString); - } - } -} \ No newline at end of file diff --git a/test/DotNetCore.CAP.EntityFrameworkCore.Test/TestHost.cs b/test/DotNetCore.CAP.EntityFrameworkCore.Test/TestHost.cs index cc69061..fbc1a94 100644 --- a/test/DotNetCore.CAP.EntityFrameworkCore.Test/TestHost.cs +++ b/test/DotNetCore.CAP.EntityFrameworkCore.Test/TestHost.cs @@ -29,7 +29,7 @@ namespace DotNetCore.CAP.EntityFrameworkCore.Test var connectionString = ConnectionUtil.GetConnectionString(); //services.AddSingleton(new SqlServerOptions { ConnectionString = connectionString }); - services.AddDbContext(options => options.UseSqlServer(connectionString)); + //services.AddDbContext(options => options.UseSqlServer(connectionString)); _services = services; } From 475ace0e952758bc961b20f96de033c3572511ea Mon Sep 17 00:00:00 2001 From: Savorboard Date: Sun, 16 Jul 2017 18:31:29 +0800 Subject: [PATCH 24/68] rename keyName to name. --- samples/Sample.Kafka/Startup.cs | 5 +- .../CAP.Options.Extensions.cs | 2 +- .../CAP.SqlServerCapOptionsExtension.cs | 15 +- .../CapDbContext.cs | 74 --------- .../CapPublisher.cs | 6 +- .../EFStorage.cs | 44 ------ .../EFStorageConnection.cs | 142 ------------------ .../EFStorageTransaction.cs | 63 -------- .../FetchedMessage.cs | 4 +- .../IAdditionalProcessor.Default.cs | 12 +- .../20170714102709_InitializeDB.Designer.cs | 91 ----------- .../Migrations/20170714102709_InitializeDB.cs | 95 ------------ .../Migrations/CapDbContextModelSnapshot.cs | 90 ----------- ...dMessage.cs => SqlServerFetchedMessage.cs} | 16 +- .../SqlServerStorage.cs | 103 +++++++++++++ .../SqlServerStorageConnection.cs | 122 +++++++++++++++ .../SqlServerStorageTransaction.cs | 73 +++++++++ src/DotNetCore.CAP/ICapPublisher.cs | 16 +- .../IConsumerHandler.Default.cs | 2 +- src/DotNetCore.CAP/IFetchedMessage.cs | 16 +- src/DotNetCore.CAP/IQueueExecutor.Subscibe.cs | 16 +- .../Infrastructure/MessageContext.cs | 2 +- src/DotNetCore.CAP/Models/CapQueue.cs | 6 +- .../Models/CapReceivedMessage.cs | 9 +- .../Processor/IDispatcher.Default.cs | 2 +- .../Processor/IProcessor.PublishQueuer.cs | 4 +- 26 files changed, 354 insertions(+), 676 deletions(-) delete mode 100644 src/DotNetCore.CAP.EntityFrameworkCore/CapDbContext.cs delete mode 100644 src/DotNetCore.CAP.EntityFrameworkCore/EFStorage.cs delete mode 100644 src/DotNetCore.CAP.EntityFrameworkCore/EFStorageConnection.cs delete mode 100644 src/DotNetCore.CAP.EntityFrameworkCore/EFStorageTransaction.cs delete mode 100644 src/DotNetCore.CAP.EntityFrameworkCore/Migrations/20170714102709_InitializeDB.Designer.cs delete mode 100644 src/DotNetCore.CAP.EntityFrameworkCore/Migrations/20170714102709_InitializeDB.cs delete mode 100644 src/DotNetCore.CAP.EntityFrameworkCore/Migrations/CapDbContextModelSnapshot.cs rename src/DotNetCore.CAP.EntityFrameworkCore/{EFFetchedMessage.cs => SqlServerFetchedMessage.cs} (82%) create mode 100644 src/DotNetCore.CAP.EntityFrameworkCore/SqlServerStorage.cs create mode 100644 src/DotNetCore.CAP.EntityFrameworkCore/SqlServerStorageConnection.cs create mode 100644 src/DotNetCore.CAP.EntityFrameworkCore/SqlServerStorageTransaction.cs diff --git a/samples/Sample.Kafka/Startup.cs b/samples/Sample.Kafka/Startup.cs index 6271903..a62ba86 100644 --- a/samples/Sample.Kafka/Startup.cs +++ b/samples/Sample.Kafka/Startup.cs @@ -25,12 +25,13 @@ namespace Sample.Kafka { services.AddDbContext(); - services.AddCap(x=> { + services.AddCap(x => + { x.UseEntityFramework(); x.UseSqlServer("Server=DESKTOP-M9R8T31;Initial Catalog=Test;User Id=sa;Password=P@ssw0rd;MultipleActiveResultSets=True"); x.UseRabbitMQ("localhost"); }); - + // Add framework services. services.AddMvc(); } diff --git a/src/DotNetCore.CAP.EntityFrameworkCore/CAP.Options.Extensions.cs b/src/DotNetCore.CAP.EntityFrameworkCore/CAP.Options.Extensions.cs index bca946f..1f2f807 100644 --- a/src/DotNetCore.CAP.EntityFrameworkCore/CAP.Options.Extensions.cs +++ b/src/DotNetCore.CAP.EntityFrameworkCore/CAP.Options.Extensions.cs @@ -44,4 +44,4 @@ namespace Microsoft.Extensions.DependencyInjection return options; } } -} +} \ No newline at end of file diff --git a/src/DotNetCore.CAP.EntityFrameworkCore/CAP.SqlServerCapOptionsExtension.cs b/src/DotNetCore.CAP.EntityFrameworkCore/CAP.SqlServerCapOptionsExtension.cs index f750980..0d0cda4 100644 --- a/src/DotNetCore.CAP.EntityFrameworkCore/CAP.SqlServerCapOptionsExtension.cs +++ b/src/DotNetCore.CAP.EntityFrameworkCore/CAP.SqlServerCapOptionsExtension.cs @@ -1,5 +1,4 @@ using System; -using Microsoft.EntityFrameworkCore; using DotNetCore.CAP.EntityFrameworkCore; using DotNetCore.CAP.Processor; using Microsoft.Extensions.DependencyInjection; @@ -17,8 +16,8 @@ namespace DotNetCore.CAP public void AddServices(IServiceCollection services) { - services.AddSingleton(); - services.AddScoped(); + services.AddSingleton(); + services.AddScoped(); services.AddScoped(); services.AddTransient(); @@ -27,16 +26,6 @@ namespace DotNetCore.CAP var sqlServerOptions = new SqlServerOptions(); _configure(sqlServerOptions); services.AddSingleton(sqlServerOptions); - - services.AddDbContext(options => - { - options.UseSqlServer(sqlServerOptions.ConnectionString, sqlOpts => - { - sqlOpts.MigrationsHistoryTable( - sqlServerOptions.MigrationsHistoryTableName, - sqlServerOptions.MigrationsHistoryTableSchema ?? sqlServerOptions.Schema); - }); - }); } } } diff --git a/src/DotNetCore.CAP.EntityFrameworkCore/CapDbContext.cs b/src/DotNetCore.CAP.EntityFrameworkCore/CapDbContext.cs deleted file mode 100644 index 0f06315..0000000 --- a/src/DotNetCore.CAP.EntityFrameworkCore/CapDbContext.cs +++ /dev/null @@ -1,74 +0,0 @@ -using System.Data.Common; -using DotNetCore.CAP.Infrastructure; -using DotNetCore.CAP.Models; -using Microsoft.EntityFrameworkCore; - -namespace DotNetCore.CAP.EntityFrameworkCore -{ - /// - /// Base class for the Entity Framework database context used for CAP. - /// - public class CapDbContext : DbContext - { - private SqlServerOptions _sqlServerOptions; - /// - /// Initializes a new instance of the . - /// - public CapDbContext() { } - - /// - /// Initializes a new instance of the . - /// - /// The options to be used by a . - public CapDbContext(DbContextOptions options, SqlServerOptions sqlServerOptions) - : base(options) { - _sqlServerOptions = sqlServerOptions; - } - - /// - /// Gets or sets the of Messages. - /// - public DbSet CapSentMessages { get; set; } - - public DbSet CapQueue { get; set; } - - /// - /// Gets or sets the of Messages. - /// - public DbSet CapReceivedMessages { get; set; } - - public DbConnection GetDbConnection() => Database.GetDbConnection(); - - /// - /// Configures the schema for the identity framework. - /// - /// - /// The builder being used to construct the model for this context. - /// - protected override void OnModelCreating(ModelBuilder modelBuilder) - { - _sqlServerOptions = new SqlServerOptions(); - modelBuilder.HasDefaultSchema(_sqlServerOptions.Schema); - - modelBuilder.Entity(b => - { - b.HasKey(m => m.Id); - b.HasIndex(x => x.StatusName); - b.Property(p => p.StatusName).IsRequired().HasMaxLength(50); - }); - - modelBuilder.Entity(b => - { - b.HasKey(m => m.Id); - b.HasIndex(x => x.StatusName); - b.Property(p => p.StatusName).IsRequired().HasMaxLength(50); - }); - } - - protected override void OnConfiguring(DbContextOptionsBuilder optionsBuilder) - { - // optionsBuilder.UseSqlServer("Server=192.168.2.206;Initial Catalog=Test;User Id=cmswuliu;Password=h7xY81agBn*Veiu3;MultipleActiveResultSets=True"); - optionsBuilder.UseSqlServer("Server=DESKTOP-M9R8T31;Initial Catalog=Test;User Id=sa;Password=P@ssw0rd;MultipleActiveResultSets=True"); - } - } -} \ No newline at end of file diff --git a/src/DotNetCore.CAP.EntityFrameworkCore/CapPublisher.cs b/src/DotNetCore.CAP.EntityFrameworkCore/CapPublisher.cs index d91b53f..8e1e65a 100644 --- a/src/DotNetCore.CAP.EntityFrameworkCore/CapPublisher.cs +++ b/src/DotNetCore.CAP.EntityFrameworkCore/CapPublisher.cs @@ -80,14 +80,14 @@ namespace DotNetCore.CAP.EntityFrameworkCore private async Task PublishWithTrans(string topic, string content, IDbConnection dbConnection, IDbTransaction dbTransaction) { - var message = new CapSentMessage + var message = new CapPublishedMessage { - KeyName = topic, + Name = topic, Content = content, StatusName = StatusName.Scheduled }; - var sql = $"INSERT INTO {_options.Schema}.[{nameof(CapDbContext.CapSentMessages)}] ([Id],[Added],[Content],[KeyName],[ExpiresAt],[Retries],[StatusName])VALUES(@Id,@Added,@Content,@KeyName,@ExpiresAt,@Retries,@StatusName)"; + var sql = $"INSERT INTO {_options.Schema}.[Published] ([Id],[Added],[Content],[KeyName],[ExpiresAt],[Retries],[StatusName])VALUES(@Id,@Added,@Content,@KeyName,@ExpiresAt,@Retries,@StatusName)"; await dbConnection.ExecuteAsync(sql, message, transaction: dbTransaction); PublishQueuer.PulseEvent.Set(); diff --git a/src/DotNetCore.CAP.EntityFrameworkCore/EFStorage.cs b/src/DotNetCore.CAP.EntityFrameworkCore/EFStorage.cs deleted file mode 100644 index 06b2d89..0000000 --- a/src/DotNetCore.CAP.EntityFrameworkCore/EFStorage.cs +++ /dev/null @@ -1,44 +0,0 @@ -using System; -using System.Threading; -using System.Threading.Tasks; -using Microsoft.EntityFrameworkCore; -using Microsoft.Extensions.DependencyInjection; -using Microsoft.Extensions.Logging; - -namespace DotNetCore.CAP.EntityFrameworkCore -{ - public class EFStorage : IStorage - { - private IServiceProvider _provider; - private ILogger _logger; - - public EFStorage( - IServiceProvider provider, - ILogger logger) - { - _provider = provider; - _logger = logger; - } - - public async Task InitializeAsync(CancellationToken cancellationToken) - { - using (var scope = _provider.CreateScope()) - { - if (cancellationToken.IsCancellationRequested) return; - - var provider = scope.ServiceProvider; - var context = provider.GetRequiredService(); - - _logger.LogDebug("Ensuring all migrations are applied to Jobs database."); - try - { - await context.Database.MigrateAsync(cancellationToken); - } - catch (Exception ex) - { - throw ex; - } - } - } - } -} diff --git a/src/DotNetCore.CAP.EntityFrameworkCore/EFStorageConnection.cs b/src/DotNetCore.CAP.EntityFrameworkCore/EFStorageConnection.cs deleted file mode 100644 index 8b38284..0000000 --- a/src/DotNetCore.CAP.EntityFrameworkCore/EFStorageConnection.cs +++ /dev/null @@ -1,142 +0,0 @@ -using System; -using System.Data; -using System.Data.SqlClient; -using System.Linq; -using System.Threading.Tasks; -using Dapper; -using DotNetCore.CAP.Infrastructure; -using DotNetCore.CAP.Models; -using Microsoft.EntityFrameworkCore; -using Microsoft.EntityFrameworkCore.Storage; -using Microsoft.Extensions.Options; - -namespace DotNetCore.CAP.EntityFrameworkCore -{ - public class EFStorageConnection : IStorageConnection - { - private readonly CapDbContext _context; - private readonly SqlServerOptions _options; - - public EFStorageConnection( - CapDbContext context, - IOptions options) - { - _context = context; - _options = options.Value; - } - - public CapDbContext Context => _context; - - public SqlServerOptions Options => _options; - - public IStorageTransaction CreateTransaction() - { - return new EFStorageTransaction(this); - } - - public Task GetSentMessageAsync(string id) - { - return _context.CapSentMessages.FirstOrDefaultAsync(x => x.Id == id); - } - - - public Task FetchNextMessageAsync() - { - var sql = $@" -DELETE TOP (1) -FROM [{_options.Schema}].[{nameof(CapDbContext.CapQueue)}] WITH (readpast, updlock, rowlock) -OUTPUT DELETED.MessageId,DELETED.[Type];"; - - return FetchNextMessageCoreAsync(sql); - } - - - public async Task GetNextSentMessageToBeEnqueuedAsync() - { - var sql = $@" -SELECT TOP (1) * -FROM [{_options.Schema}].[{nameof(CapDbContext.CapSentMessages)}] WITH (readpast) -WHERE StatusName = '{StatusName.Scheduled}'"; - - var connection = _context.GetDbConnection(); - var message = (await connection.QueryAsync(sql)).FirstOrDefault(); - - if (message != null) - { - _context.Attach(message); - } - - return message; - } - - // CapReceviedMessage - - public Task StoreReceivedMessageAsync(CapReceivedMessage message) - { - if (message == null) throw new ArgumentNullException(nameof(message)); - - _context.Add(message); - return _context.SaveChangesAsync(); - } - - public Task GetReceivedMessageAsync(string id) - { - return _context.CapReceivedMessages.FirstOrDefaultAsync(x => x.Id == id); - } - - public async Task GetNextReceviedMessageToBeEnqueuedAsync() - { - var sql = $@" -SELECT TOP (1) * -FROM [{_options.Schema}].[{nameof(CapDbContext.CapReceivedMessages)}] WITH (readpast) -WHERE StatusName = '{StatusName.Enqueued}'"; - - var connection = _context.GetDbConnection(); - var message = (await connection.QueryAsync(sql)).FirstOrDefault(); - - if (message != null) - { - _context.Attach(message); - } - - return message; - } - - public void Dispose() - { - } - - private async Task FetchNextMessageCoreAsync(string sql, object args = null) - { - FetchedMessage fetchedMessage = null; - var connection = _context.GetDbConnection(); - var transaction = _context.Database.CurrentTransaction; - transaction = transaction ?? await _context.Database.BeginTransactionAsync(IsolationLevel.ReadCommitted); - - try - { - fetchedMessage = - (await connection.QueryAsync(sql, args, transaction.GetDbTransaction())) - .FirstOrDefault(); - } - catch (SqlException) - { - transaction.Dispose(); - throw; - } - - if (fetchedMessage == null) - { - transaction.Rollback(); - transaction.Dispose(); - return null; - } - - return new EFFetchedMessage( - fetchedMessage.MessageId, - fetchedMessage.Type, - connection, - transaction); - } - } -} diff --git a/src/DotNetCore.CAP.EntityFrameworkCore/EFStorageTransaction.cs b/src/DotNetCore.CAP.EntityFrameworkCore/EFStorageTransaction.cs deleted file mode 100644 index ed38d9e..0000000 --- a/src/DotNetCore.CAP.EntityFrameworkCore/EFStorageTransaction.cs +++ /dev/null @@ -1,63 +0,0 @@ -using System; -using System.Threading.Tasks; -using DotNetCore.CAP.Models; - -namespace DotNetCore.CAP.EntityFrameworkCore -{ - public class EFStorageTransaction - : IStorageTransaction, IDisposable - { - private EFStorageConnection _connection; - - public EFStorageTransaction(EFStorageConnection connection) - { - _connection = connection; - } - - public void UpdateMessage(CapSentMessage message) - { - if (message == null) throw new ArgumentNullException(nameof(message)); - - // NOOP. EF will detect changes. - } - - public void UpdateMessage(CapReceivedMessage message) - { - if (message == null) throw new ArgumentNullException(nameof(message)); - - // NOOP. EF will detect changes. - } - - public void EnqueueMessage(CapSentMessage message) - { - if (message == null) throw new ArgumentNullException(nameof(message)); - - _connection.Context.Add(new CapQueue - { - MessageId = message.Id, - Type = 0 - }); - } - - public void EnqueueMessage(CapReceivedMessage message) - { - if (message == null) throw new ArgumentNullException(nameof(message)); - - _connection.Context.Add(new CapQueue - { - MessageId = message.Id, - Type = MessageType.Subscribe - }); - } - - - public Task CommitAsync() - { - return _connection.Context.SaveChangesAsync(); - } - - public void Dispose() - { - } - } -} diff --git a/src/DotNetCore.CAP.EntityFrameworkCore/FetchedMessage.cs b/src/DotNetCore.CAP.EntityFrameworkCore/FetchedMessage.cs index b1827e1..5e9fad2 100644 --- a/src/DotNetCore.CAP.EntityFrameworkCore/FetchedMessage.cs +++ b/src/DotNetCore.CAP.EntityFrameworkCore/FetchedMessage.cs @@ -7,8 +7,8 @@ namespace DotNetCore.CAP.EntityFrameworkCore { public class FetchedMessage { - public string MessageId { get; set; } + public int MessageId { get; set; } - public MessageType Type { get; set; } + public MessageType MessageType { get; set; } } } diff --git a/src/DotNetCore.CAP.EntityFrameworkCore/IAdditionalProcessor.Default.cs b/src/DotNetCore.CAP.EntityFrameworkCore/IAdditionalProcessor.Default.cs index 4014e4d..fe31d0a 100644 --- a/src/DotNetCore.CAP.EntityFrameworkCore/IAdditionalProcessor.Default.cs +++ b/src/DotNetCore.CAP.EntityFrameworkCore/IAdditionalProcessor.Default.cs @@ -1,5 +1,6 @@ using System; using System.Collections.Generic; +using System.Data.SqlClient; using System.Text; using System.Threading.Tasks; using Dapper; @@ -21,8 +22,7 @@ namespace DotNetCore.CAP.EntityFrameworkCore private static readonly string[] Tables = { - nameof(CapDbContext.CapSentMessages), - nameof(CapDbContext.CapReceivedMessages), + "Published","Received" }; public DefaultAdditionalProcessor( @@ -44,18 +44,14 @@ namespace DotNetCore.CAP.EntityFrameworkCore var removedCount = 0; do { - using (var scope = _provider.CreateScope()) + using(var connection = new SqlConnection(_options.ConnectionString)) { - var provider = scope.ServiceProvider; - var jobsDbContext = provider.GetService(); - var connection = jobsDbContext.GetDbConnection(); - removedCount = await connection.ExecuteAsync($@" DELETE TOP (@count) FROM [{_options.Schema}].[{table}] WITH (readpast) WHERE ExpiresAt < @now;", new { now = DateTime.Now, count = MaxBatch }); } - + if (removedCount != 0) { await context.WaitAsync(_delay); diff --git a/src/DotNetCore.CAP.EntityFrameworkCore/Migrations/20170714102709_InitializeDB.Designer.cs b/src/DotNetCore.CAP.EntityFrameworkCore/Migrations/20170714102709_InitializeDB.Designer.cs deleted file mode 100644 index 5d5fb40..0000000 --- a/src/DotNetCore.CAP.EntityFrameworkCore/Migrations/20170714102709_InitializeDB.Designer.cs +++ /dev/null @@ -1,91 +0,0 @@ -using System; -using Microsoft.EntityFrameworkCore; -using Microsoft.EntityFrameworkCore.Infrastructure; -using Microsoft.EntityFrameworkCore.Metadata; -using Microsoft.EntityFrameworkCore.Migrations; -using DotNetCore.CAP.EntityFrameworkCore; -using DotNetCore.CAP.Models; - -namespace DotNetCore.CAP.EntityFrameworkCore.Migrations -{ - [DbContext(typeof(CapDbContext))] - [Migration("20170714102709_InitializeDB")] - partial class InitializeDB - { - protected override void BuildTargetModel(ModelBuilder modelBuilder) - { - modelBuilder - .HasDefaultSchema("cap") - .HasAnnotation("ProductVersion", "1.1.2") - .HasAnnotation("SqlServer:ValueGenerationStrategy", SqlServerValueGenerationStrategy.IdentityColumn); - - modelBuilder.Entity("DotNetCore.CAP.Models.CapQueue", b => - { - b.Property("Id") - .ValueGeneratedOnAdd(); - - b.Property("MessageId"); - - b.Property("Type"); - - b.HasKey("Id"); - - b.ToTable("CapQueue"); - }); - - modelBuilder.Entity("DotNetCore.CAP.Models.CapReceivedMessage", b => - { - b.Property("Id") - .ValueGeneratedOnAdd(); - - b.Property("Added"); - - b.Property("Content"); - - b.Property("ExpiresAt"); - - b.Property("Group"); - - b.Property("KeyName"); - - b.Property("Retries"); - - b.Property("StatusName") - .IsRequired() - .HasMaxLength(50); - - b.HasKey("Id"); - - b.HasIndex("StatusName"); - - b.ToTable("CapReceivedMessages"); - }); - - modelBuilder.Entity("DotNetCore.CAP.Models.CapSentMessage", b => - { - b.Property("Id") - .ValueGeneratedOnAdd(); - - b.Property("Added"); - - b.Property("Content"); - - b.Property("ExpiresAt"); - - b.Property("KeyName"); - - b.Property("Retries"); - - b.Property("StatusName") - .IsRequired() - .HasMaxLength(50); - - b.HasKey("Id"); - - b.HasIndex("StatusName"); - - b.ToTable("CapSentMessages"); - }); - } - } -} diff --git a/src/DotNetCore.CAP.EntityFrameworkCore/Migrations/20170714102709_InitializeDB.cs b/src/DotNetCore.CAP.EntityFrameworkCore/Migrations/20170714102709_InitializeDB.cs deleted file mode 100644 index 4607b1e..0000000 --- a/src/DotNetCore.CAP.EntityFrameworkCore/Migrations/20170714102709_InitializeDB.cs +++ /dev/null @@ -1,95 +0,0 @@ -using System; -using System.Collections.Generic; -using Microsoft.EntityFrameworkCore.Migrations; -using Microsoft.EntityFrameworkCore.Metadata; - -namespace DotNetCore.CAP.EntityFrameworkCore.Migrations -{ - public partial class InitializeDB : Migration - { - protected override void Up(MigrationBuilder migrationBuilder) - { - migrationBuilder.EnsureSchema( - name: "cap"); - - migrationBuilder.CreateTable( - name: "CapQueue", - schema: "cap", - columns: table => new - { - Id = table.Column(nullable: false) - .Annotation("SqlServer:ValueGenerationStrategy", SqlServerValueGenerationStrategy.IdentityColumn), - MessageId = table.Column(nullable: true), - Type = table.Column(nullable: false) - }, - constraints: table => - { - table.PrimaryKey("PK_CapQueue", x => x.Id); - }); - - migrationBuilder.CreateTable( - name: "CapReceivedMessages", - schema: "cap", - columns: table => new - { - Id = table.Column(nullable: false), - Added = table.Column(nullable: false), - Content = table.Column(nullable: true), - ExpiresAt = table.Column(nullable: true), - Group = table.Column(nullable: true), - KeyName = table.Column(nullable: true), - Retries = table.Column(nullable: false), - StatusName = table.Column(maxLength: 50, nullable: false) - }, - constraints: table => - { - table.PrimaryKey("PK_CapReceivedMessages", x => x.Id); - }); - - migrationBuilder.CreateTable( - name: "CapSentMessages", - schema: "cap", - columns: table => new - { - Id = table.Column(nullable: false), - Added = table.Column(nullable: false), - Content = table.Column(nullable: true), - ExpiresAt = table.Column(nullable: true), - KeyName = table.Column(nullable: true), - Retries = table.Column(nullable: false), - StatusName = table.Column(maxLength: 50, nullable: false) - }, - constraints: table => - { - table.PrimaryKey("PK_CapSentMessages", x => x.Id); - }); - - migrationBuilder.CreateIndex( - name: "IX_CapReceivedMessages_StatusName", - schema: "cap", - table: "CapReceivedMessages", - column: "StatusName"); - - migrationBuilder.CreateIndex( - name: "IX_CapSentMessages_StatusName", - schema: "cap", - table: "CapSentMessages", - column: "StatusName"); - } - - protected override void Down(MigrationBuilder migrationBuilder) - { - migrationBuilder.DropTable( - name: "CapQueue", - schema: "cap"); - - migrationBuilder.DropTable( - name: "CapReceivedMessages", - schema: "cap"); - - migrationBuilder.DropTable( - name: "CapSentMessages", - schema: "cap"); - } - } -} diff --git a/src/DotNetCore.CAP.EntityFrameworkCore/Migrations/CapDbContextModelSnapshot.cs b/src/DotNetCore.CAP.EntityFrameworkCore/Migrations/CapDbContextModelSnapshot.cs deleted file mode 100644 index 63f1770..0000000 --- a/src/DotNetCore.CAP.EntityFrameworkCore/Migrations/CapDbContextModelSnapshot.cs +++ /dev/null @@ -1,90 +0,0 @@ -using System; -using Microsoft.EntityFrameworkCore; -using Microsoft.EntityFrameworkCore.Infrastructure; -using Microsoft.EntityFrameworkCore.Metadata; -using Microsoft.EntityFrameworkCore.Migrations; -using DotNetCore.CAP.EntityFrameworkCore; -using DotNetCore.CAP.Models; - -namespace DotNetCore.CAP.EntityFrameworkCore.Migrations -{ - [DbContext(typeof(CapDbContext))] - partial class CapDbContextModelSnapshot : ModelSnapshot - { - protected override void BuildModel(ModelBuilder modelBuilder) - { - modelBuilder - .HasDefaultSchema("cap") - .HasAnnotation("ProductVersion", "1.1.2") - .HasAnnotation("SqlServer:ValueGenerationStrategy", SqlServerValueGenerationStrategy.IdentityColumn); - - modelBuilder.Entity("DotNetCore.CAP.Models.CapQueue", b => - { - b.Property("Id") - .ValueGeneratedOnAdd(); - - b.Property("MessageId"); - - b.Property("Type"); - - b.HasKey("Id"); - - b.ToTable("CapQueue"); - }); - - modelBuilder.Entity("DotNetCore.CAP.Models.CapReceivedMessage", b => - { - b.Property("Id") - .ValueGeneratedOnAdd(); - - b.Property("Added"); - - b.Property("Content"); - - b.Property("ExpiresAt"); - - b.Property("Group"); - - b.Property("KeyName"); - - b.Property("Retries"); - - b.Property("StatusName") - .IsRequired() - .HasMaxLength(50); - - b.HasKey("Id"); - - b.HasIndex("StatusName"); - - b.ToTable("CapReceivedMessages"); - }); - - modelBuilder.Entity("DotNetCore.CAP.Models.CapSentMessage", b => - { - b.Property("Id") - .ValueGeneratedOnAdd(); - - b.Property("Added"); - - b.Property("Content"); - - b.Property("ExpiresAt"); - - b.Property("KeyName"); - - b.Property("Retries"); - - b.Property("StatusName") - .IsRequired() - .HasMaxLength(50); - - b.HasKey("Id"); - - b.HasIndex("StatusName"); - - b.ToTable("CapSentMessages"); - }); - } - } -} diff --git a/src/DotNetCore.CAP.EntityFrameworkCore/EFFetchedMessage.cs b/src/DotNetCore.CAP.EntityFrameworkCore/SqlServerFetchedMessage.cs similarity index 82% rename from src/DotNetCore.CAP.EntityFrameworkCore/EFFetchedMessage.cs rename to src/DotNetCore.CAP.EntityFrameworkCore/SqlServerFetchedMessage.cs index 8e75f3f..0a0004e 100644 --- a/src/DotNetCore.CAP.EntityFrameworkCore/EFFetchedMessage.cs +++ b/src/DotNetCore.CAP.EntityFrameworkCore/SqlServerFetchedMessage.cs @@ -9,29 +9,29 @@ using Microsoft.EntityFrameworkCore.Storage; namespace DotNetCore.CAP.EntityFrameworkCore { - public class EFFetchedMessage : IFetchedMessage + public class SqlServerFetchedMessage : IFetchedMessage { private readonly IDbConnection _connection; - private readonly IDbContextTransaction _transaction; + private readonly IDbTransaction _transaction; private readonly Timer _timer; private static readonly TimeSpan KeepAliveInterval = TimeSpan.FromMinutes(1); private readonly object _lockObject = new object(); - public EFFetchedMessage(string messageId, + public SqlServerFetchedMessage(int messageId, MessageType type, IDbConnection connection, - IDbContextTransaction transaction) + IDbTransaction transaction) { MessageId = messageId; - Type = type; + MessageType = type; _connection = connection; _transaction = transaction; _timer = new Timer(ExecuteKeepAliveQuery, null, KeepAliveInterval, KeepAliveInterval); } - public string MessageId { get; } + public int MessageId { get; } - public MessageType Type { get; } + public MessageType MessageType { get; } public void RemoveFromQueue() { @@ -65,7 +65,7 @@ namespace DotNetCore.CAP.EntityFrameworkCore { try { - _connection?.Execute("SELECT 1", _transaction.GetDbTransaction()); + _connection?.Execute("SELECT 1", _transaction); } catch { diff --git a/src/DotNetCore.CAP.EntityFrameworkCore/SqlServerStorage.cs b/src/DotNetCore.CAP.EntityFrameworkCore/SqlServerStorage.cs new file mode 100644 index 0000000..4d29987 --- /dev/null +++ b/src/DotNetCore.CAP.EntityFrameworkCore/SqlServerStorage.cs @@ -0,0 +1,103 @@ +using System; +using System.Data.SqlClient; +using System.Threading; +using System.Threading.Tasks; +using Dapper; +using Microsoft.EntityFrameworkCore; +using Microsoft.Extensions.DependencyInjection; +using Microsoft.Extensions.Logging; + +namespace DotNetCore.CAP.EntityFrameworkCore +{ + public class SqlServerStorage : IStorage + { + private IServiceProvider _provider; + private ILogger _logger; + + public SqlServerStorage( + IServiceProvider provider, + ILogger logger) + { + _provider = provider; + _logger = logger; + } + + public async Task InitializeAsync(CancellationToken cancellationToken) + { + using (var scope = _provider.CreateScope()) + { + if (cancellationToken.IsCancellationRequested) return; + + var provider = scope.ServiceProvider; + var options = provider.GetRequiredService(); + + var sql = CreateDbTablesScript(options.Schema); + + using (var connection = new SqlConnection(options.ConnectionString)) + { + await connection.ExecuteAsync(sql); + } + _logger.LogDebug("Ensuring all create database tables script are applied."); + } + } + + protected virtual string CreateDbTablesScript(string schema) + { + + var batchSQL = +$@" +IF NOT EXISTS (SELECT * FROM sys.schemas WHERE name = '{schema}') +BEGIN + EXEC('CREATE SCHEMA {schema}') +END +GO + +IF OBJECT_ID(N'[{schema}].[Queue]',N'U') IS NULL +BEGIN + CREATE TABLE [{schema}].[Queue]( + [MessageId] [int] NOT NULL, + [MessageType] [tinyint] NOT NULL + ) ON [PRIMARY] +END +GO + +IF OBJECT_ID(N'[{schema}].[Received]',N'U') IS NULL +BEGIN +CREATE TABLE [{schema}].[Received]( + [Id] [int] IDENTITY(1,1) NOT NULL, + [Name] [nvarchar](200) NOT NULL, + [Group] [nvarchar](200) NULL, + [Content] [nvarchar](max) NULL, + [Retries] [int] NOT NULL, + [Added] [datetime2](7) NOT NULL, + [ExpiresAt] [datetime2](7) NULL, + [StatusName] [nvarchar](50) NOT NULL, + CONSTRAINT [PK_{schema}.Received] PRIMARY KEY CLUSTERED +( + [Id] ASC +)WITH (PAD_INDEX = OFF, STATISTICS_NORECOMPUTE = OFF, IGNORE_DUP_KEY = OFF, ALLOW_ROW_LOCKS = ON, ALLOW_PAGE_LOCKS = ON) ON [PRIMARY] +) ON [PRIMARY] TEXTIMAGE_ON [PRIMARY] +END +GO + +IF OBJECT_ID(N'[{schema}].[Published]',N'U') IS NULL +BEGIN +CREATE TABLE [{schema}].[Published]( + [Id] [int] IDENTITY(1,1) NOT NULL, + [Name] [nvarchar](200) NOT NULL, + [Content] [nvarchar](max) NULL, + [Retries] [int] NOT NULL, + [Added] [datetime2](7) NOT NULL, + [ExpiresAt] [datetime2](7) NULL, + [StatusName] [nvarchar](50) NOT NULL, + CONSTRAINT [PK_{schema}.Published] PRIMARY KEY CLUSTERED +( + [Id] ASC +)WITH (PAD_INDEX = OFF, STATISTICS_NORECOMPUTE = OFF, IGNORE_DUP_KEY = OFF, ALLOW_ROW_LOCKS = ON, ALLOW_PAGE_LOCKS = ON) ON [PRIMARY] +) ON [PRIMARY] TEXTIMAGE_ON [PRIMARY] +END +GO"; + return batchSQL; + } + } +} diff --git a/src/DotNetCore.CAP.EntityFrameworkCore/SqlServerStorageConnection.cs b/src/DotNetCore.CAP.EntityFrameworkCore/SqlServerStorageConnection.cs new file mode 100644 index 0000000..96929c6 --- /dev/null +++ b/src/DotNetCore.CAP.EntityFrameworkCore/SqlServerStorageConnection.cs @@ -0,0 +1,122 @@ +using System; +using System.Data; +using System.Data.SqlClient; +using System.Threading.Tasks; +using Dapper; +using DotNetCore.CAP.Infrastructure; +using DotNetCore.CAP.Models; +using Microsoft.EntityFrameworkCore; +using Microsoft.Extensions.Options; + +namespace DotNetCore.CAP.EntityFrameworkCore +{ + public class SqlServerStorageConnection : IStorageConnection + { + private readonly SqlServerOptions _options; + + public SqlServerStorageConnection(IOptions options) + { + _options = options.Value; + } + + public SqlServerOptions Options => _options; + + public IStorageTransaction CreateTransaction() + { + return new SqlServerStorageTransaction(this); + } + + public Task GetPublishedMessageAsync(int id) + { + var sql = $@"SELECT * FROM [{_options.Schema}].[Published] WITH (readpast) WHERE Id={id}"; + using (var connection = new SqlConnection(_options.ConnectionString)) + { + return connection.QueryFirstOrDefaultAsync(sql); + } + } + + public Task FetchNextMessageAsync() + { + var sql = $@" +DELETE TOP (1) +FROM [{_options.Schema}].[Queue] WITH (readpast, updlock, rowlock) +OUTPUT DELETED.MessageId,DELETED.[MessageType];"; + + return FetchNextMessageCoreAsync(sql); + } + + public async Task GetNextPublishedMessageToBeEnqueuedAsync() + { + var sql = $"SELECT TOP (1) * FROM [{_options.Schema}].[Published] WITH (readpast) WHERE StatusName = '{StatusName.Scheduled}'"; + + using (var connection = new SqlConnection(_options.ConnectionString)) + { + return await connection.QueryFirstOrDefaultAsync(sql); + } + } + + // CapReceviedMessage + + public Task StoreReceivedMessageAsync(CapReceivedMessage message) + { + if (message == null) throw new ArgumentNullException(nameof(message)); + + var sql = $@" +INSERT INTO [{_options.Schema}].[Received]([Name],[Group],[Content],[Retries],[Added],[ExpiresAt],[StatusName]) +VALUES(@Name,@Group,@Content,@Retries,@Added,@ExpiresAt,@StatusName);"; + + using (var connection = new SqlConnection(_options.ConnectionString)) + { + return connection.ExecuteAsync(sql, message); + } + } + + public Task GetReceivedMessageAsync(int id) + { + var sql = $@"SELECT * FROM [{_options.Schema}].[Received] WITH (readpast) WHERE Id={id}"; + using (var connection = new SqlConnection(_options.ConnectionString)) + { + return connection.QueryFirstOrDefaultAsync(sql); + } + } + + public async Task GetNextReceviedMessageToBeEnqueuedAsync() + { + var sql = $"SELECT TOP (1) * FROM [{_options.Schema}].[Received] WITH (readpast) WHERE StatusName = '{StatusName.Scheduled}'"; + using (var connection = new SqlConnection(_options.ConnectionString)) + { + return await connection.QueryFirstOrDefaultAsync(sql); + } + } + + public void Dispose() + { + } + + private async Task FetchNextMessageCoreAsync(string sql, object args = null) + { + FetchedMessage fetched = null; + + using (var connection = new SqlConnection(_options.ConnectionString)) + { + using (var transaction = connection.BeginTransaction(IsolationLevel.ReadCommitted)) + { + try + { + fetched = await connection.QueryFirstOrDefaultAsync(sql, args, transaction); + + if (fetched == null) + return null; + + return new SqlServerFetchedMessage(fetched.MessageId, fetched.MessageType, connection, transaction); + } + catch (Exception) + { + transaction.Rollback(); + return null; + } + } + } + } + } +} \ No newline at end of file diff --git a/src/DotNetCore.CAP.EntityFrameworkCore/SqlServerStorageTransaction.cs b/src/DotNetCore.CAP.EntityFrameworkCore/SqlServerStorageTransaction.cs new file mode 100644 index 0000000..e0cdcf3 --- /dev/null +++ b/src/DotNetCore.CAP.EntityFrameworkCore/SqlServerStorageTransaction.cs @@ -0,0 +1,73 @@ +using System; +using System.Data; +using System.Data.SqlClient; +using System.Threading.Tasks; +using Dapper; +using DotNetCore.CAP.Models; + +namespace DotNetCore.CAP.EntityFrameworkCore +{ + public class SqlServerStorageTransaction : IStorageTransaction, IDisposable + { + private readonly SqlServerStorageConnection _connection; + private readonly SqlServerOptions _options; + private readonly string _schema; + + private IDbTransaction _dbTransaction; + private IDbConnection _dbConnection; + + public SqlServerStorageTransaction(SqlServerStorageConnection connection) + { + _connection = connection; + _options = _connection.Options; + _schema = _options.Schema; + + _dbConnection = new SqlConnection(_options.ConnectionString); + _dbTransaction = _dbConnection.BeginTransaction(IsolationLevel.ReadCommitted); + } + + public void UpdateMessage(CapPublishedMessage message) + { + if (message == null) throw new ArgumentNullException(nameof(message)); + + var sql = $"UPDATE [{_schema}].[Published] SET [ExpiresAt] = @ExpiresAt,[StatusName]=@StatusName WHERE Id=@Id;"; + _dbConnection.Execute(sql, message); + } + + public void UpdateMessage(CapReceivedMessage message) + { + if (message == null) throw new ArgumentNullException(nameof(message)); + + var sql = $"UPDATE [{_schema}].[Received] SET [ExpiresAt] = @ExpiresAt,[StatusName]=@StatusName WHERE Id=@Id;"; + _dbConnection.Execute(sql, message); + } + + public void EnqueueMessage(CapPublishedMessage message) + { + if (message == null) throw new ArgumentNullException(nameof(message)); + + var sql = $"INSERT INTO [{_schema}].[Queue] values(@MessageId,@MessageType);"; + _dbConnection.Execute(sql, new CapQueue { MessageId = message.Id, MessageType = MessageType.Publish }); + } + + public void EnqueueMessage(CapReceivedMessage message) + { + if (message == null) throw new ArgumentNullException(nameof(message)); + + var sql = $"INSERT INTO [{_schema}].[Queue] values(@MessageId,@MessageType);"; + _dbConnection.Execute(sql, new CapQueue { MessageId = message.Id, MessageType = MessageType.Subscribe }); + } + + public Task CommitAsync() + { + _dbTransaction.Commit(); + return Task.CompletedTask; + } + + public void Dispose() + { + _dbTransaction.Dispose(); + _dbConnection.Dispose(); + } + } +} \ No newline at end of file diff --git a/src/DotNetCore.CAP/ICapPublisher.cs b/src/DotNetCore.CAP/ICapPublisher.cs index aff0c5e..50c4a50 100644 --- a/src/DotNetCore.CAP/ICapPublisher.cs +++ b/src/DotNetCore.CAP/ICapPublisher.cs @@ -16,9 +16,9 @@ namespace DotNetCore.CAP /// otherwise you need to use overloaded method with IDbConnection and IDbTransaction. /// /// - /// the topic name or exchange router key. + /// the topic name or exchange router key. /// message body content. - Task PublishAsync(string topic, string content); + Task PublishAsync(string name, string content); /// /// Publis a object message to specified topic. @@ -28,25 +28,25 @@ namespace DotNetCore.CAP /// /// /// The type of conetent object. - /// the topic name or exchange router key. + /// the topic name or exchange router key. /// object instance that will be serialized of json. - Task PublishAsync(string topic, T contentObj); + Task PublishAsync(string name, T contentObj); /// /// Publish a string message to specified topic with transacton. /// - /// the topic name or exchange router key. + /// the topic name or exchange router key. /// message body content. /// the dbConnection of - Task PublishAsync(string topic, string content, IDbConnection dbConnection); + Task PublishAsync(string name, string content, IDbConnection dbConnection); /// /// Publish a string message to specified topic with transacton. /// - /// the topic name or exchange router key. + /// the topic name or exchange router key. /// message body content. /// the connection of /// the transaction of - Task PublishAsync(string topic, string content, IDbConnection dbConnection, IDbTransaction dbTransaction); + Task PublishAsync(string name, string content, IDbConnection dbConnection, IDbTransaction dbTransaction); } } \ No newline at end of file diff --git a/src/DotNetCore.CAP/IConsumerHandler.Default.cs b/src/DotNetCore.CAP/IConsumerHandler.Default.cs index d84a669..b56eeea 100644 --- a/src/DotNetCore.CAP/IConsumerHandler.Default.cs +++ b/src/DotNetCore.CAP/IConsumerHandler.Default.cs @@ -101,7 +101,7 @@ namespace DotNetCore.CAP { client.MessageReceieved += (sender, message) => { - _logger.EnqueuingReceivedMessage(message.KeyName, message.Content); + _logger.EnqueuingReceivedMessage(message.Name, message.Content); using (var scope = _serviceProvider.CreateScope()) { diff --git a/src/DotNetCore.CAP/IFetchedMessage.cs b/src/DotNetCore.CAP/IFetchedMessage.cs index ce5897c..ca7acee 100644 --- a/src/DotNetCore.CAP/IFetchedMessage.cs +++ b/src/DotNetCore.CAP/IFetchedMessage.cs @@ -3,14 +3,14 @@ using DotNetCore.CAP.Models; namespace DotNetCore.CAP { - public interface IFetchedMessage : IDisposable - { - string MessageId { get; } + public interface IFetchedMessage : IDisposable + { + int MessageId { get; } - MessageType Type { get; } + MessageType MessageType { get; } - void RemoveFromQueue(); + void RemoveFromQueue(); - void Requeue(); - } -} + void Requeue(); + } +} \ No newline at end of file diff --git a/src/DotNetCore.CAP/IQueueExecutor.Subscibe.cs b/src/DotNetCore.CAP/IQueueExecutor.Subscibe.cs index d69cdf4..e771455 100644 --- a/src/DotNetCore.CAP/IQueueExecutor.Subscibe.cs +++ b/src/DotNetCore.CAP/IQueueExecutor.Subscibe.cs @@ -1,15 +1,12 @@ using System; -using System.Collections.Generic; using System.Diagnostics; -using System.Text; -using System.Threading; using System.Threading.Tasks; using DotNetCore.CAP.Abstractions; using DotNetCore.CAP.Infrastructure; using DotNetCore.CAP.Internal; +using DotNetCore.CAP.Models; using DotNetCore.CAP.Processor; using DotNetCore.CAP.Processor.States; -using DotNetCore.CAP.Models; using Microsoft.Extensions.Logging; namespace DotNetCore.CAP @@ -92,7 +89,7 @@ namespace DotNetCore.CAP } catch (Exception ex) { - _logger.ExceptionOccuredWhileExecutingJob(message?.KeyName, ex); + _logger.ExceptionOccuredWhileExecutingJob(message?.Name, ex); return OperateResult.Failed(ex); } } @@ -102,11 +99,11 @@ namespace DotNetCore.CAP { try { - var executeDescriptorGroup = _selector.GetTopicExector(receivedMessage.KeyName); + var executeDescriptorGroup = _selector.GetTopicExector(receivedMessage.Name); if (!executeDescriptorGroup.ContainsKey(receivedMessage.Group)) { - throw new SubscriberNotFoundException(receivedMessage.KeyName + " has not been found."); + throw new SubscriberNotFoundException(receivedMessage.Name + " has not been found."); } // If there are multiple consumers in the same group, we will take the first @@ -123,7 +120,7 @@ namespace DotNetCore.CAP } catch (Exception ex) { - _logger.ConsumerMethodExecutingFailed($"Group:{receivedMessage.Group}, Topic:{receivedMessage.KeyName}", ex); + _logger.ConsumerMethodExecutingFailed($"Group:{receivedMessage.Group}, Topic:{receivedMessage.Name}", ex); return OperateResult.Failed(ex); } } @@ -148,6 +145,5 @@ namespace DotNetCore.CAP } return true; } - } -} +} \ No newline at end of file diff --git a/src/DotNetCore.CAP/Infrastructure/MessageContext.cs b/src/DotNetCore.CAP/Infrastructure/MessageContext.cs index 48982d6..6f8dfe8 100644 --- a/src/DotNetCore.CAP/Infrastructure/MessageContext.cs +++ b/src/DotNetCore.CAP/Infrastructure/MessageContext.cs @@ -4,7 +4,7 @@ { public string Group { get; set; } - public string KeyName { get; set; } + public string Name { get; set; } public string Content { get; set; } } diff --git a/src/DotNetCore.CAP/Models/CapQueue.cs b/src/DotNetCore.CAP/Models/CapQueue.cs index 229ecef..e8c0da1 100644 --- a/src/DotNetCore.CAP/Models/CapQueue.cs +++ b/src/DotNetCore.CAP/Models/CapQueue.cs @@ -2,13 +2,11 @@ { public class CapQueue { - public int Id { get; set; } - - public string MessageId { get; set; } + public int MessageId { get; set; } /// /// 0 is CapSentMessage, 1 is CapReceviedMessage /// - public MessageType Type { get; set; } + public MessageType MessageType { get; set; } } } diff --git a/src/DotNetCore.CAP/Models/CapReceivedMessage.cs b/src/DotNetCore.CAP/Models/CapReceivedMessage.cs index dfa5624..bfb0103 100644 --- a/src/DotNetCore.CAP/Models/CapReceivedMessage.cs +++ b/src/DotNetCore.CAP/Models/CapReceivedMessage.cs @@ -13,22 +13,21 @@ namespace DotNetCore.CAP.Models /// public CapReceivedMessage() { - Id = Guid.NewGuid().ToString(); Added = DateTime.Now; } public CapReceivedMessage(MessageContext message) : this() { Group = message.Group; - KeyName = message.KeyName; + Name = message.Name; Content = message.Content; } - public string Id { get; set; } + public int Id { get; set; } public string Group { get; set; } - public string KeyName { get; set; } + public string Name { get; set; } public string Content { get; set; } @@ -45,7 +44,7 @@ namespace DotNetCore.CAP.Models return new MessageContext { Group = Group, - KeyName = KeyName, + Name = Name, Content = Content }; } diff --git a/src/DotNetCore.CAP/Processor/IDispatcher.Default.cs b/src/DotNetCore.CAP/Processor/IDispatcher.Default.cs index be0aa4f..1066ddf 100644 --- a/src/DotNetCore.CAP/Processor/IDispatcher.Default.cs +++ b/src/DotNetCore.CAP/Processor/IDispatcher.Default.cs @@ -85,7 +85,7 @@ namespace DotNetCore.CAP.Processor { using (fetched) { - var queueExecutor = _queueExecutorFactory.GetInstance(fetched.Type); + var queueExecutor = _queueExecutorFactory.GetInstance(fetched.MessageType); await queueExecutor.ExecuteAsync(connection, fetched); } } diff --git a/src/DotNetCore.CAP/Processor/IProcessor.PublishQueuer.cs b/src/DotNetCore.CAP/Processor/IProcessor.PublishQueuer.cs index 9de598e..ec0faf3 100644 --- a/src/DotNetCore.CAP/Processor/IProcessor.PublishQueuer.cs +++ b/src/DotNetCore.CAP/Processor/IProcessor.PublishQueuer.cs @@ -38,13 +38,13 @@ namespace DotNetCore.CAP.Processor { using (var scope = _provider.CreateScope()) { - CapSentMessage sentMessage; + CapPublishedMessage sentMessage; var provider = scope.ServiceProvider; var connection = provider.GetRequiredService(); while ( !context.IsStopping && - (sentMessage = await connection.GetNextSentMessageToBeEnqueuedAsync()) != null) + (sentMessage = await connection.GetNextPublishedMessageToBeEnqueuedAsync()) != null) { var state = new EnqueuedState(); From cd25f37213fc92768b26d161891713b4c0358570 Mon Sep 17 00:00:00 2001 From: yangxiaodong Date: Mon, 17 Jul 2017 10:37:36 +0800 Subject: [PATCH 25/68] support cancellation token of consumer handler. --- src/DotNetCore.CAP.Kafka/KafkaConsumerClient.cs | 4 +++- .../RabbitMQConsumerClient.cs | 5 +++-- src/DotNetCore.CAP/IBootstrapper.Default.cs | 2 -- src/DotNetCore.CAP/IConsumerClient.cs | 3 ++- src/DotNetCore.CAP/IConsumerHandler.Default.cs | 13 +++++-------- 5 files changed, 13 insertions(+), 14 deletions(-) diff --git a/src/DotNetCore.CAP.Kafka/KafkaConsumerClient.cs b/src/DotNetCore.CAP.Kafka/KafkaConsumerClient.cs index ad79353..a3c5503 100644 --- a/src/DotNetCore.CAP.Kafka/KafkaConsumerClient.cs +++ b/src/DotNetCore.CAP.Kafka/KafkaConsumerClient.cs @@ -1,5 +1,6 @@ using System; using System.Text; +using System.Threading; using Confluent.Kafka; using Confluent.Kafka.Serialization; using DotNetCore.CAP.Infrastructure; @@ -38,10 +39,11 @@ namespace DotNetCore.CAP.Kafka _consumerClient.Subscribe(topicName); } - public void Listening(TimeSpan timeout) + public void Listening(TimeSpan timeout, CancellationToken cancellationToken) { while (true) { + cancellationToken.ThrowIfCancellationRequested(); _consumerClient.Poll(timeout); } } diff --git a/src/DotNetCore.CAP.RabbitMQ/RabbitMQConsumerClient.cs b/src/DotNetCore.CAP.RabbitMQ/RabbitMQConsumerClient.cs index 35bbcc0..9ca8a86 100644 --- a/src/DotNetCore.CAP.RabbitMQ/RabbitMQConsumerClient.cs +++ b/src/DotNetCore.CAP.RabbitMQ/RabbitMQConsumerClient.cs @@ -1,5 +1,6 @@ using System; using System.Text; +using System.Threading; using System.Threading.Tasks; using DotNetCore.CAP.Infrastructure; using RabbitMQ.Client; @@ -49,14 +50,14 @@ namespace DotNetCore.CAP.RabbitMQ _channel.QueueDeclare(_queueName, exclusive: false); } - public void Listening(TimeSpan timeout) + public void Listening(TimeSpan timeout, CancellationToken cancellationToken) { var consumer = new EventingBasicConsumer(_channel); consumer.Received += OnConsumerReceived; _channel.BasicConsume(_queueName, false, consumer); while (true) { - Task.Delay(timeout).Wait(); + Task.Delay(timeout, cancellationToken).Wait(); } } diff --git a/src/DotNetCore.CAP/IBootstrapper.Default.cs b/src/DotNetCore.CAP/IBootstrapper.Default.cs index 58bfe58..09b9291 100644 --- a/src/DotNetCore.CAP/IBootstrapper.Default.cs +++ b/src/DotNetCore.CAP/IBootstrapper.Default.cs @@ -68,8 +68,6 @@ namespace DotNetCore.CAP if (_cts.IsCancellationRequested) return; - if (_cts.IsCancellationRequested) return; - await BootstrapCoreAsync(); if (_cts.IsCancellationRequested) return; diff --git a/src/DotNetCore.CAP/IConsumerClient.cs b/src/DotNetCore.CAP/IConsumerClient.cs index e3dc29d..c59c20c 100644 --- a/src/DotNetCore.CAP/IConsumerClient.cs +++ b/src/DotNetCore.CAP/IConsumerClient.cs @@ -1,4 +1,5 @@ using System; +using System.Threading; using DotNetCore.CAP.Infrastructure; namespace DotNetCore.CAP @@ -12,7 +13,7 @@ namespace DotNetCore.CAP void Subscribe(string topic, int partition); - void Listening(TimeSpan timeout); + void Listening(TimeSpan timeout, CancellationToken cancellationToken); void Commit(); diff --git a/src/DotNetCore.CAP/IConsumerHandler.Default.cs b/src/DotNetCore.CAP/IConsumerHandler.Default.cs index b56eeea..706fb64 100644 --- a/src/DotNetCore.CAP/IConsumerHandler.Default.cs +++ b/src/DotNetCore.CAP/IConsumerHandler.Default.cs @@ -2,7 +2,6 @@ using System.Linq; using System.Threading; using System.Threading.Tasks; -using DotNetCore.CAP.Abstractions; using DotNetCore.CAP.Infrastructure; using DotNetCore.CAP.Internal; using DotNetCore.CAP.Models; @@ -18,12 +17,11 @@ namespace DotNetCore.CAP private readonly IServiceProvider _serviceProvider; private readonly IConsumerInvokerFactory _consumerInvokerFactory; private readonly IConsumerClientFactory _consumerClientFactory; - private readonly ILoggerFactory _loggerFactory; private readonly ILogger _logger; + private readonly CancellationTokenSource _cts; private readonly MethodMatcherCache _selector; private readonly CapOptions _options; - private readonly CancellationTokenSource _cts; private readonly TimeSpan _pollingDelay = TimeSpan.FromSeconds(1); @@ -34,13 +32,12 @@ namespace DotNetCore.CAP IServiceProvider serviceProvider, IConsumerInvokerFactory consumerInvokerFactory, IConsumerClientFactory consumerClientFactory, - ILoggerFactory loggerFactory, + ILogger logger, MethodMatcherCache selector, IOptions options) { _selector = selector; - _logger = loggerFactory.CreateLogger(); - _loggerFactory = loggerFactory; + _logger = logger; _serviceProvider = serviceProvider; _consumerInvokerFactory = consumerInvokerFactory; _consumerClientFactory = consumerClientFactory; @@ -65,7 +62,7 @@ namespace DotNetCore.CAP client.Subscribe(item.Attribute.Name); } - client.Listening(_pollingDelay); + client.Listening(_pollingDelay, _cts.Token); } }, _cts.Token, TaskCreationOptions.LongRunning, TaskScheduler.Default); } @@ -85,7 +82,7 @@ namespace DotNetCore.CAP try { - _compositeTask.Wait((int)TimeSpan.FromSeconds(60).TotalMilliseconds); + _compositeTask.Wait(TimeSpan.FromSeconds(60)); } catch (AggregateException ex) { From 821544b24b0f6334f6b8945d910d8c7f17a02962 Mon Sep 17 00:00:00 2001 From: yangxiaodong Date: Mon, 17 Jul 2017 10:51:26 +0800 Subject: [PATCH 26/68] add expriseAt --- .../Processor/States/IStateChanger.Default.cs | 39 ++++++++++--------- 1 file changed, 20 insertions(+), 19 deletions(-) diff --git a/src/DotNetCore.CAP/Processor/States/IStateChanger.Default.cs b/src/DotNetCore.CAP/Processor/States/IStateChanger.Default.cs index b8b419b..1982e46 100644 --- a/src/DotNetCore.CAP/Processor/States/IStateChanger.Default.cs +++ b/src/DotNetCore.CAP/Processor/States/IStateChanger.Default.cs @@ -1,4 +1,5 @@ -using DotNetCore.CAP.Models; +using System; +using DotNetCore.CAP.Models; namespace DotNetCore.CAP.Processor.States { @@ -6,15 +7,15 @@ namespace DotNetCore.CAP.Processor.States { public void ChangeState(CapPublishedMessage message, IState state, IStorageTransaction transaction) { - //var now = DateTime.UtcNow; - //if (state.ExpiresAfter != null) - //{ - // message.ExpiresAt = now.Add(state.ExpiresAfter.Value); - //} - //else - //{ - // message.ExpiresAt = null; - //} + var now = DateTime.Now; + if (state.ExpiresAfter != null) + { + message.ExpiresAt = now.Add(state.ExpiresAfter.Value); + } + else + { + message.ExpiresAt = null; + } message.StatusName = state.Name; state.Apply(message, transaction); @@ -23,15 +24,15 @@ namespace DotNetCore.CAP.Processor.States public void ChangeState(CapReceivedMessage message, IState state, IStorageTransaction transaction) { - //var now = DateTime.UtcNow; - //if (state.ExpiresAfter != null) - //{ - // job.ExpiresAt = now.Add(state.ExpiresAfter.Value); - //} - //else - //{ - // job.ExpiresAt = null; - //} + var now = DateTime.Now; + if (state.ExpiresAfter != null) + { + message.ExpiresAt = now.Add(state.ExpiresAfter.Value); + } + else + { + message.ExpiresAt = null; + } message.StatusName = state.Name; state.Apply(message, transaction); From 819c4465aeb8df8638976e25bbf7044b7fbe0292 Mon Sep 17 00:00:00 2001 From: yangxiaodong Date: Mon, 17 Jul 2017 10:54:54 +0800 Subject: [PATCH 27/68] cleanup code. --- .../CAP.EFOptions.cs | 4 +- .../CAP.SqlServerCapOptionsExtension.cs | 2 +- .../CAP.SqlServerOptions.cs | 10 +-- .../CapPublisher.cs | 2 +- .../FetchedMessage.cs | 7 +- .../IAdditionalProcessor.Default.cs | 9 +-- .../SqlServerFetchedMessage.cs | 5 +- .../SqlServerStorage.cs | 7 +- .../CAP.KafkaCapOptionsExtension.cs | 2 +- src/DotNetCore.CAP.Kafka/CAP.KafkaOptions.cs | 4 +- .../CAP.Options.Extensions.cs | 1 - .../KafkaConsumerClient.cs | 1 - .../PublishQueueExecutor.cs | 2 +- .../CAP.RabbiMQOptions.cs | 2 +- .../CAP.RabbitMQCapOptionsExtension.cs | 2 +- .../CapSubscribeAttribute.cs | 1 - .../PublishQueueExecutor.cs | 3 +- .../Abstractions/ModelBinding/IModelBinder.cs | 2 +- src/DotNetCore.CAP/CAP.Options.cs | 1 - .../CAP.ServiceCollectionExtensions.cs | 4 +- src/DotNetCore.CAP/ICapOptionsExtension.cs | 2 +- src/DotNetCore.CAP/ICapPublisher.cs | 5 +- .../IConsumerHandler.Default.cs | 1 - src/DotNetCore.CAP/IQueueExecutor.cs | 7 +- src/DotNetCore.CAP/IStorage.cs | 22 +++--- src/DotNetCore.CAP/IStorageTransaction.cs | 18 ++--- src/DotNetCore.CAP/Infrastructure/Helper.cs | 2 +- .../Infrastructure/StatusName.cs | 8 +- .../Infrastructure/WaitHandleEx.cs | 2 +- .../IConsumerServiceSelector.Default.cs | 1 - .../Internal/MethodMatcherCache.cs | 4 +- .../Internal/ObjectMethodExecutor.cs | 6 +- .../Internal/SubscriberNotFoundException.cs | 14 +++- src/DotNetCore.CAP/LoggerExtensions.cs | 7 -- .../Models/CapPublishedMessage.cs | 4 +- src/DotNetCore.CAP/Models/CapQueue.cs | 2 +- src/DotNetCore.CAP/Models/MessageType.cs | 2 +- src/DotNetCore.CAP/OperateResult.cs | 4 +- .../Processor/IAdditionalProcessor.cs | 9 +-- .../Processor/IDispatcher.Default.cs | 2 +- src/DotNetCore.CAP/Processor/IDispatcher.cs | 8 +- .../Processor/IProcessor.PublishQueuer.cs | 76 +++++++++---------- .../Processor/IProcessor.SubscribeQueuer.cs | 4 +- src/DotNetCore.CAP/Processor/RetryBehavior.cs | 2 +- src/DotNetCore.CAP/QueueExecutorFactory.cs | 6 +- 45 files changed, 123 insertions(+), 166 deletions(-) diff --git a/src/DotNetCore.CAP.EntityFrameworkCore/CAP.EFOptions.cs b/src/DotNetCore.CAP.EntityFrameworkCore/CAP.EFOptions.cs index 78ce66b..a742b2a 100644 --- a/src/DotNetCore.CAP.EntityFrameworkCore/CAP.EFOptions.cs +++ b/src/DotNetCore.CAP.EntityFrameworkCore/CAP.EFOptions.cs @@ -1,6 +1,4 @@ using System; -using System.Collections.Generic; -using System.Text; namespace DotNetCore.CAP { @@ -29,4 +27,4 @@ namespace DotNetCore.CAP public Type DbContextType { get; internal set; } } -} +} \ No newline at end of file diff --git a/src/DotNetCore.CAP.EntityFrameworkCore/CAP.SqlServerCapOptionsExtension.cs b/src/DotNetCore.CAP.EntityFrameworkCore/CAP.SqlServerCapOptionsExtension.cs index 0d0cda4..8f60f34 100644 --- a/src/DotNetCore.CAP.EntityFrameworkCore/CAP.SqlServerCapOptionsExtension.cs +++ b/src/DotNetCore.CAP.EntityFrameworkCore/CAP.SqlServerCapOptionsExtension.cs @@ -28,4 +28,4 @@ namespace DotNetCore.CAP services.AddSingleton(sqlServerOptions); } } -} +} \ No newline at end of file diff --git a/src/DotNetCore.CAP.EntityFrameworkCore/CAP.SqlServerOptions.cs b/src/DotNetCore.CAP.EntityFrameworkCore/CAP.SqlServerOptions.cs index 817e045..40a2d4f 100644 --- a/src/DotNetCore.CAP.EntityFrameworkCore/CAP.SqlServerOptions.cs +++ b/src/DotNetCore.CAP.EntityFrameworkCore/CAP.SqlServerOptions.cs @@ -1,9 +1,4 @@ -using System; -using System.Collections.Generic; -using System.Text; -using DotNetCore.CAP.EntityFrameworkCore; - -namespace DotNetCore.CAP +namespace DotNetCore.CAP { public class SqlServerOptions : EFOptions { @@ -11,6 +6,5 @@ namespace DotNetCore.CAP /// Gets or sets the database's connection string that will be used to store database entities. /// public string ConnectionString { get; set; } //= "Server=DESKTOP-M9R8T31;Initial Catalog=Test;User Id=sa;Password=P@ssw0rd;MultipleActiveResultSets=True"; - } -} +} \ No newline at end of file diff --git a/src/DotNetCore.CAP.EntityFrameworkCore/CapPublisher.cs b/src/DotNetCore.CAP.EntityFrameworkCore/CapPublisher.cs index 8e1e65a..13a8700 100644 --- a/src/DotNetCore.CAP.EntityFrameworkCore/CapPublisher.cs +++ b/src/DotNetCore.CAP.EntityFrameworkCore/CapPublisher.cs @@ -93,4 +93,4 @@ namespace DotNetCore.CAP.EntityFrameworkCore PublishQueuer.PulseEvent.Set(); } } -} +} \ No newline at end of file diff --git a/src/DotNetCore.CAP.EntityFrameworkCore/FetchedMessage.cs b/src/DotNetCore.CAP.EntityFrameworkCore/FetchedMessage.cs index 5e9fad2..13dbc0f 100644 --- a/src/DotNetCore.CAP.EntityFrameworkCore/FetchedMessage.cs +++ b/src/DotNetCore.CAP.EntityFrameworkCore/FetchedMessage.cs @@ -1,7 +1,4 @@ -using System; -using System.Collections.Generic; -using System.Text; -using DotNetCore.CAP.Models; +using DotNetCore.CAP.Models; namespace DotNetCore.CAP.EntityFrameworkCore { @@ -11,4 +8,4 @@ namespace DotNetCore.CAP.EntityFrameworkCore public MessageType MessageType { get; set; } } -} +} \ No newline at end of file diff --git a/src/DotNetCore.CAP.EntityFrameworkCore/IAdditionalProcessor.Default.cs b/src/DotNetCore.CAP.EntityFrameworkCore/IAdditionalProcessor.Default.cs index fe31d0a..89126ac 100644 --- a/src/DotNetCore.CAP.EntityFrameworkCore/IAdditionalProcessor.Default.cs +++ b/src/DotNetCore.CAP.EntityFrameworkCore/IAdditionalProcessor.Default.cs @@ -1,11 +1,8 @@ using System; -using System.Collections.Generic; using System.Data.SqlClient; -using System.Text; using System.Threading.Tasks; using Dapper; using DotNetCore.CAP.Processor; -using Microsoft.Extensions.DependencyInjection; using Microsoft.Extensions.Logging; namespace DotNetCore.CAP.EntityFrameworkCore @@ -44,14 +41,14 @@ namespace DotNetCore.CAP.EntityFrameworkCore var removedCount = 0; do { - using(var connection = new SqlConnection(_options.ConnectionString)) + using (var connection = new SqlConnection(_options.ConnectionString)) { removedCount = await connection.ExecuteAsync($@" DELETE TOP (@count) FROM [{_options.Schema}].[{table}] WITH (readpast) WHERE ExpiresAt < @now;", new { now = DateTime.Now, count = MaxBatch }); } - + if (removedCount != 0) { await context.WaitAsync(_delay); @@ -63,4 +60,4 @@ WHERE ExpiresAt < @now;", new { now = DateTime.Now, count = MaxBatch }); await context.WaitAsync(_waitingInterval); } } -} +} \ No newline at end of file diff --git a/src/DotNetCore.CAP.EntityFrameworkCore/SqlServerFetchedMessage.cs b/src/DotNetCore.CAP.EntityFrameworkCore/SqlServerFetchedMessage.cs index 0a0004e..e93167d 100644 --- a/src/DotNetCore.CAP.EntityFrameworkCore/SqlServerFetchedMessage.cs +++ b/src/DotNetCore.CAP.EntityFrameworkCore/SqlServerFetchedMessage.cs @@ -1,11 +1,8 @@ using System; -using System.Collections.Generic; using System.Data; -using System.Text; using System.Threading; using Dapper; using DotNetCore.CAP.Models; -using Microsoft.EntityFrameworkCore.Storage; namespace DotNetCore.CAP.EntityFrameworkCore { @@ -73,4 +70,4 @@ namespace DotNetCore.CAP.EntityFrameworkCore } } } -} +} \ No newline at end of file diff --git a/src/DotNetCore.CAP.EntityFrameworkCore/SqlServerStorage.cs b/src/DotNetCore.CAP.EntityFrameworkCore/SqlServerStorage.cs index 4d29987..b5b73bb 100644 --- a/src/DotNetCore.CAP.EntityFrameworkCore/SqlServerStorage.cs +++ b/src/DotNetCore.CAP.EntityFrameworkCore/SqlServerStorage.cs @@ -43,7 +43,6 @@ namespace DotNetCore.CAP.EntityFrameworkCore protected virtual string CreateDbTablesScript(string schema) { - var batchSQL = $@" IF NOT EXISTS (SELECT * FROM sys.schemas WHERE name = '{schema}') @@ -72,7 +71,7 @@ CREATE TABLE [{schema}].[Received]( [Added] [datetime2](7) NOT NULL, [ExpiresAt] [datetime2](7) NULL, [StatusName] [nvarchar](50) NOT NULL, - CONSTRAINT [PK_{schema}.Received] PRIMARY KEY CLUSTERED + CONSTRAINT [PK_{schema}.Received] PRIMARY KEY CLUSTERED ( [Id] ASC )WITH (PAD_INDEX = OFF, STATISTICS_NORECOMPUTE = OFF, IGNORE_DUP_KEY = OFF, ALLOW_ROW_LOCKS = ON, ALLOW_PAGE_LOCKS = ON) ON [PRIMARY] @@ -90,7 +89,7 @@ CREATE TABLE [{schema}].[Published]( [Added] [datetime2](7) NOT NULL, [ExpiresAt] [datetime2](7) NULL, [StatusName] [nvarchar](50) NOT NULL, - CONSTRAINT [PK_{schema}.Published] PRIMARY KEY CLUSTERED + CONSTRAINT [PK_{schema}.Published] PRIMARY KEY CLUSTERED ( [Id] ASC )WITH (PAD_INDEX = OFF, STATISTICS_NORECOMPUTE = OFF, IGNORE_DUP_KEY = OFF, ALLOW_ROW_LOCKS = ON, ALLOW_PAGE_LOCKS = ON) ON [PRIMARY] @@ -100,4 +99,4 @@ GO"; return batchSQL; } } -} +} \ No newline at end of file diff --git a/src/DotNetCore.CAP.Kafka/CAP.KafkaCapOptionsExtension.cs b/src/DotNetCore.CAP.Kafka/CAP.KafkaCapOptionsExtension.cs index 2a6466c..42df3f8 100644 --- a/src/DotNetCore.CAP.Kafka/CAP.KafkaCapOptionsExtension.cs +++ b/src/DotNetCore.CAP.Kafka/CAP.KafkaCapOptionsExtension.cs @@ -25,4 +25,4 @@ namespace DotNetCore.CAP services.AddTransient(); } } -} +} \ No newline at end of file diff --git a/src/DotNetCore.CAP.Kafka/CAP.KafkaOptions.cs b/src/DotNetCore.CAP.Kafka/CAP.KafkaOptions.cs index 1c09b77..55b055b 100644 --- a/src/DotNetCore.CAP.Kafka/CAP.KafkaOptions.cs +++ b/src/DotNetCore.CAP.Kafka/CAP.KafkaOptions.cs @@ -32,9 +32,9 @@ namespace DotNetCore.CAP internal IEnumerable> AsRdkafkaConfig() { - if (MainConfig.ContainsKey("bootstrap.servers")) + if (MainConfig.ContainsKey("bootstrap.servers")) return MainConfig.AsEnumerable(); - + if (string.IsNullOrEmpty(Servers)) { throw new ArgumentNullException(nameof(Servers)); diff --git a/src/DotNetCore.CAP.Kafka/CAP.Options.Extensions.cs b/src/DotNetCore.CAP.Kafka/CAP.Options.Extensions.cs index 8afeece..c562251 100644 --- a/src/DotNetCore.CAP.Kafka/CAP.Options.Extensions.cs +++ b/src/DotNetCore.CAP.Kafka/CAP.Options.Extensions.cs @@ -1,6 +1,5 @@ using System; using DotNetCore.CAP; -using DotNetCore.CAP.Kafka; namespace Microsoft.Extensions.DependencyInjection { diff --git a/src/DotNetCore.CAP.Kafka/KafkaConsumerClient.cs b/src/DotNetCore.CAP.Kafka/KafkaConsumerClient.cs index a3c5503..014c9bd 100644 --- a/src/DotNetCore.CAP.Kafka/KafkaConsumerClient.cs +++ b/src/DotNetCore.CAP.Kafka/KafkaConsumerClient.cs @@ -81,7 +81,6 @@ namespace DotNetCore.CAP.Kafka MessageReceieved?.Invoke(sender, message); } - #endregion private methods } } \ No newline at end of file diff --git a/src/DotNetCore.CAP.Kafka/PublishQueueExecutor.cs b/src/DotNetCore.CAP.Kafka/PublishQueueExecutor.cs index e54975b..8252629 100644 --- a/src/DotNetCore.CAP.Kafka/PublishQueueExecutor.cs +++ b/src/DotNetCore.CAP.Kafka/PublishQueueExecutor.cs @@ -51,4 +51,4 @@ namespace DotNetCore.CAP.Kafka } } } -} +} \ No newline at end of file diff --git a/src/DotNetCore.CAP.RabbitMQ/CAP.RabbiMQOptions.cs b/src/DotNetCore.CAP.RabbitMQ/CAP.RabbiMQOptions.cs index de82129..ddce147 100644 --- a/src/DotNetCore.CAP.RabbitMQ/CAP.RabbiMQOptions.cs +++ b/src/DotNetCore.CAP.RabbitMQ/CAP.RabbiMQOptions.cs @@ -72,7 +72,7 @@ public int SocketWriteTimeout { get; set; } = DefaultConnectionTimeout; /// - /// The port to connect on. + /// The port to connect on. /// public int Port { get; set; } = -1; } diff --git a/src/DotNetCore.CAP.RabbitMQ/CAP.RabbitMQCapOptionsExtension.cs b/src/DotNetCore.CAP.RabbitMQ/CAP.RabbitMQCapOptionsExtension.cs index 17f7faa..ee677c8 100644 --- a/src/DotNetCore.CAP.RabbitMQ/CAP.RabbitMQCapOptionsExtension.cs +++ b/src/DotNetCore.CAP.RabbitMQ/CAP.RabbitMQCapOptionsExtension.cs @@ -26,4 +26,4 @@ namespace DotNetCore.CAP services.AddTransient(); } } -} +} \ No newline at end of file diff --git a/src/DotNetCore.CAP.RabbitMQ/CapSubscribeAttribute.cs b/src/DotNetCore.CAP.RabbitMQ/CapSubscribeAttribute.cs index cfbbc8d..de63ac7 100644 --- a/src/DotNetCore.CAP.RabbitMQ/CapSubscribeAttribute.cs +++ b/src/DotNetCore.CAP.RabbitMQ/CapSubscribeAttribute.cs @@ -6,7 +6,6 @@ namespace DotNetCore.CAP.RabbitMQ { public CapSubscribeAttribute(string name) : base(name) { - } } } \ No newline at end of file diff --git a/src/DotNetCore.CAP.RabbitMQ/PublishQueueExecutor.cs b/src/DotNetCore.CAP.RabbitMQ/PublishQueueExecutor.cs index df08dd2..80f0cfb 100644 --- a/src/DotNetCore.CAP.RabbitMQ/PublishQueueExecutor.cs +++ b/src/DotNetCore.CAP.RabbitMQ/PublishQueueExecutor.cs @@ -64,7 +64,6 @@ namespace DotNetCore.CAP.RabbitMQ Description = ex.Message })); } - } } -} +} \ No newline at end of file diff --git a/src/DotNetCore.CAP/Abstractions/ModelBinding/IModelBinder.cs b/src/DotNetCore.CAP/Abstractions/ModelBinding/IModelBinder.cs index c8c976c..f03b105 100644 --- a/src/DotNetCore.CAP/Abstractions/ModelBinding/IModelBinder.cs +++ b/src/DotNetCore.CAP/Abstractions/ModelBinding/IModelBinder.cs @@ -14,7 +14,7 @@ namespace DotNetCore.CAP.Abstractions.ModelBinding /// /// /// A which will complete when the model binding process completes. - /// + /// /// Task BindModelAsync(ModelBindingContext bindingContext); } diff --git a/src/DotNetCore.CAP/CAP.Options.cs b/src/DotNetCore.CAP/CAP.Options.cs index 003f6c0..de6d1ae 100644 --- a/src/DotNetCore.CAP/CAP.Options.cs +++ b/src/DotNetCore.CAP/CAP.Options.cs @@ -35,7 +35,6 @@ namespace DotNetCore.CAP /// public int PollingDelay { get; set; } = 8; - /// /// Registers an extension that will be executed when building services. /// diff --git a/src/DotNetCore.CAP/CAP.ServiceCollectionExtensions.cs b/src/DotNetCore.CAP/CAP.ServiceCollectionExtensions.cs index f6fda76..2ba0faa 100644 --- a/src/DotNetCore.CAP/CAP.ServiceCollectionExtensions.cs +++ b/src/DotNetCore.CAP/CAP.ServiceCollectionExtensions.cs @@ -47,12 +47,12 @@ namespace Microsoft.Extensions.DependencyInjection //Processors services.AddTransient(); services.AddTransient(); - services.AddTransient(); + services.AddTransient(); //Executors services.AddSingleton(); services.AddSingleton(); - + //Options var options = new CapOptions(); setupAction(options); diff --git a/src/DotNetCore.CAP/ICapOptionsExtension.cs b/src/DotNetCore.CAP/ICapOptionsExtension.cs index 5e29f50..bfeb693 100644 --- a/src/DotNetCore.CAP/ICapOptionsExtension.cs +++ b/src/DotNetCore.CAP/ICapOptionsExtension.cs @@ -6,4 +6,4 @@ namespace DotNetCore.CAP { void AddServices(IServiceCollection services); } -} +} \ No newline at end of file diff --git a/src/DotNetCore.CAP/ICapPublisher.cs b/src/DotNetCore.CAP/ICapPublisher.cs index 50c4a50..95f28b0 100644 --- a/src/DotNetCore.CAP/ICapPublisher.cs +++ b/src/DotNetCore.CAP/ICapPublisher.cs @@ -1,5 +1,4 @@ -using System; -using System.Data; +using System.Data; using System.Threading.Tasks; namespace DotNetCore.CAP @@ -21,7 +20,7 @@ namespace DotNetCore.CAP Task PublishAsync(string name, string content); /// - /// Publis a object message to specified topic. + /// Publis a object message to specified topic. /// /// If you are using the EntityFramework, you need to configure the DbContextType first. /// otherwise you need to use overloaded method with IDbConnection and IDbTransaction. diff --git a/src/DotNetCore.CAP/IConsumerHandler.Default.cs b/src/DotNetCore.CAP/IConsumerHandler.Default.cs index 706fb64..0ca1949 100644 --- a/src/DotNetCore.CAP/IConsumerHandler.Default.cs +++ b/src/DotNetCore.CAP/IConsumerHandler.Default.cs @@ -1,5 +1,4 @@ using System; -using System.Linq; using System.Threading; using System.Threading.Tasks; using DotNetCore.CAP.Infrastructure; diff --git a/src/DotNetCore.CAP/IQueueExecutor.cs b/src/DotNetCore.CAP/IQueueExecutor.cs index 7135eed..ad4a6b1 100644 --- a/src/DotNetCore.CAP/IQueueExecutor.cs +++ b/src/DotNetCore.CAP/IQueueExecutor.cs @@ -1,7 +1,4 @@ -using System; -using System.Collections.Generic; -using System.Text; -using System.Threading.Tasks; +using System.Threading.Tasks; namespace DotNetCore.CAP { @@ -9,4 +6,4 @@ namespace DotNetCore.CAP { Task ExecuteAsync(IStorageConnection connection, IFetchedMessage message); } -} +} \ No newline at end of file diff --git a/src/DotNetCore.CAP/IStorage.cs b/src/DotNetCore.CAP/IStorage.cs index 1140411..ea5726d 100644 --- a/src/DotNetCore.CAP/IStorage.cs +++ b/src/DotNetCore.CAP/IStorage.cs @@ -3,14 +3,14 @@ using System.Threading.Tasks; namespace DotNetCore.CAP { - /// - /// Represents a persisted storage. - /// - public interface IStorage - { - /// - /// Initializes the storage. For example, making sure a database is created and migrations are applied. - /// - Task InitializeAsync(CancellationToken cancellationToken); - } -} + /// + /// Represents a persisted storage. + /// + public interface IStorage + { + /// + /// Initializes the storage. For example, making sure a database is created and migrations are applied. + /// + Task InitializeAsync(CancellationToken cancellationToken); + } +} \ No newline at end of file diff --git a/src/DotNetCore.CAP/IStorageTransaction.cs b/src/DotNetCore.CAP/IStorageTransaction.cs index 642cc4d..788d4e1 100644 --- a/src/DotNetCore.CAP/IStorageTransaction.cs +++ b/src/DotNetCore.CAP/IStorageTransaction.cs @@ -4,16 +4,16 @@ using DotNetCore.CAP.Models; namespace DotNetCore.CAP { - public interface IStorageTransaction : IDisposable - { - void UpdateMessage(CapPublishedMessage message); + public interface IStorageTransaction : IDisposable + { + void UpdateMessage(CapPublishedMessage message); - void UpdateMessage(CapReceivedMessage message); + void UpdateMessage(CapReceivedMessage message); - void EnqueueMessage(CapPublishedMessage message); + void EnqueueMessage(CapPublishedMessage message); - void EnqueueMessage(CapReceivedMessage message); + void EnqueueMessage(CapReceivedMessage message); - Task CommitAsync(); - } -} + Task CommitAsync(); + } +} \ No newline at end of file diff --git a/src/DotNetCore.CAP/Infrastructure/Helper.cs b/src/DotNetCore.CAP/Infrastructure/Helper.cs index e254fed..a4c36e2 100644 --- a/src/DotNetCore.CAP/Infrastructure/Helper.cs +++ b/src/DotNetCore.CAP/Infrastructure/Helper.cs @@ -40,7 +40,7 @@ namespace DotNetCore.CAP.Infrastructure public static long ToTimestamp(DateTime value) { var elapsedTime = value - Epoch; - return (long) elapsedTime.TotalSeconds; + return (long)elapsedTime.TotalSeconds; } public static DateTime FromTimestamp(long value) diff --git a/src/DotNetCore.CAP/Infrastructure/StatusName.cs b/src/DotNetCore.CAP/Infrastructure/StatusName.cs index 2841d84..62ee0fd 100644 --- a/src/DotNetCore.CAP/Infrastructure/StatusName.cs +++ b/src/DotNetCore.CAP/Infrastructure/StatusName.cs @@ -1,8 +1,4 @@ -using System; -using System.Collections.Generic; -using System.Text; - -namespace DotNetCore.CAP.Infrastructure +namespace DotNetCore.CAP.Infrastructure { /// /// The message status name. @@ -15,4 +11,4 @@ namespace DotNetCore.CAP.Infrastructure public const string Succeeded = nameof(Succeeded); public const string Failed = nameof(Failed); } -} +} \ No newline at end of file diff --git a/src/DotNetCore.CAP/Infrastructure/WaitHandleEx.cs b/src/DotNetCore.CAP/Infrastructure/WaitHandleEx.cs index 5a277d2..4afa6d6 100644 --- a/src/DotNetCore.CAP/Infrastructure/WaitHandleEx.cs +++ b/src/DotNetCore.CAP/Infrastructure/WaitHandleEx.cs @@ -21,7 +21,7 @@ namespace DotNetCore.CAP.Infrastructure var tcs = new TaskCompletionSource(); registeredHandle = ThreadPool.RegisterWaitForSingleObject( handle, - (state, timedOut) => ((TaskCompletionSource) state).TrySetResult(!timedOut), + (state, timedOut) => ((TaskCompletionSource)state).TrySetResult(!timedOut), tcs, timeout, true); diff --git a/src/DotNetCore.CAP/Internal/IConsumerServiceSelector.Default.cs b/src/DotNetCore.CAP/Internal/IConsumerServiceSelector.Default.cs index 44721d2..ab67b97 100644 --- a/src/DotNetCore.CAP/Internal/IConsumerServiceSelector.Default.cs +++ b/src/DotNetCore.CAP/Internal/IConsumerServiceSelector.Default.cs @@ -44,7 +44,6 @@ namespace DotNetCore.CAP.Internal return executorDescriptorList; } - private static IEnumerable FindConsumersFromInterfaceTypes( IServiceProvider provider) { diff --git a/src/DotNetCore.CAP/Internal/MethodMatcherCache.cs b/src/DotNetCore.CAP/Internal/MethodMatcherCache.cs index 0483ab7..332158b 100644 --- a/src/DotNetCore.CAP/Internal/MethodMatcherCache.cs +++ b/src/DotNetCore.CAP/Internal/MethodMatcherCache.cs @@ -1,7 +1,7 @@ using System; -using System.Linq; using System.Collections.Concurrent; using System.Collections.Generic; +using System.Linq; using DotNetCore.CAP.Abstractions; namespace DotNetCore.CAP.Internal @@ -41,7 +41,7 @@ namespace DotNetCore.CAP.Internal /// /// Get a dictionary of specify topic candidates. - /// The Key is Group name, the value is specify topic candidates. + /// The Key is Group name, the value is specify topic candidates. /// /// message topic name public IDictionary> GetTopicExector(string topicName) diff --git a/src/DotNetCore.CAP/Internal/ObjectMethodExecutor.cs b/src/DotNetCore.CAP/Internal/ObjectMethodExecutor.cs index ca81421..cb0f99d 100644 --- a/src/DotNetCore.CAP/Internal/ObjectMethodExecutor.cs +++ b/src/DotNetCore.CAP/Internal/ObjectMethodExecutor.cs @@ -130,7 +130,7 @@ namespace DotNetCore.CAP.Internal private static ConsumerMethodExecutor WrapVoidAction(VoidActionExecutor executor) { - return delegate(object target, object[] parameters) + return delegate (object target, object[] parameters) { executor(target, parameters); return null; @@ -192,7 +192,7 @@ namespace DotNetCore.CAP.Internal /// private static async Task CastToObject(Task task) { - return (object) await task; + return (object)await task; } private static Type GetTaskInnerTypeOrNull(Type type) @@ -279,7 +279,7 @@ namespace DotNetCore.CAP.Internal private static Task Convert(object taskAsObject) { - var task = (Task) taskAsObject; + var task = (Task)taskAsObject; return CastToObject(task); } diff --git a/src/DotNetCore.CAP/Internal/SubscriberNotFoundException.cs b/src/DotNetCore.CAP/Internal/SubscriberNotFoundException.cs index 4bf9844..4889a8a 100644 --- a/src/DotNetCore.CAP/Internal/SubscriberNotFoundException.cs +++ b/src/DotNetCore.CAP/Internal/SubscriberNotFoundException.cs @@ -1,13 +1,19 @@ using System; + namespace DotNetCore.CAP.Internal { public class SubscriberNotFoundException : Exception { - public SubscriberNotFoundException() { } + public SubscriberNotFoundException() + { + } - public SubscriberNotFoundException(string message) : base(message) { } + public SubscriberNotFoundException(string message) : base(message) + { + } public SubscriberNotFoundException(string message, Exception inner) : - base(message, inner) { } + base(message, inner) + { } } -} +} \ No newline at end of file diff --git a/src/DotNetCore.CAP/LoggerExtensions.cs b/src/DotNetCore.CAP/LoggerExtensions.cs index 5bb3ee5..c921247 100644 --- a/src/DotNetCore.CAP/LoggerExtensions.cs +++ b/src/DotNetCore.CAP/LoggerExtensions.cs @@ -1,7 +1,4 @@ using System; -using System.Collections.Generic; -using System.Linq; -using DotNetCore.CAP.Processor; using Microsoft.Extensions.Logging; namespace DotNetCore.CAP @@ -66,7 +63,6 @@ namespace DotNetCore.CAP 5, "Received message topic method '{topicName}' failed to execute."); - _jobRetrying = LoggerMessage.Define( LogLevel.Debug, 3, @@ -104,19 +100,16 @@ namespace DotNetCore.CAP _jobFailedWillRetry(logger, ex); } - public static void JobRetrying(this ILogger logger, int retries) { _jobRetrying(logger, retries, null); } - public static void JobExecuted(this ILogger logger, double seconds) { _jobExecuted(logger, seconds, null); } - public static void ConsumerMethodExecutingFailed(this ILogger logger, string methodName, Exception ex) { _executingConsumerMethod(logger, methodName, ex); diff --git a/src/DotNetCore.CAP/Models/CapPublishedMessage.cs b/src/DotNetCore.CAP/Models/CapPublishedMessage.cs index 7780a09..24dfbcc 100644 --- a/src/DotNetCore.CAP/Models/CapPublishedMessage.cs +++ b/src/DotNetCore.CAP/Models/CapPublishedMessage.cs @@ -3,7 +3,7 @@ using DotNetCore.CAP.Infrastructure; namespace DotNetCore.CAP.Models { - public class CapPublishedMessage + public class CapPublishedMessage { /// /// Initializes a new instance of . @@ -22,7 +22,7 @@ namespace DotNetCore.CAP.Models Content = message.Content; } - public int Id { get; set; } + public int Id { get; set; } public string Name { get; set; } diff --git a/src/DotNetCore.CAP/Models/CapQueue.cs b/src/DotNetCore.CAP/Models/CapQueue.cs index e8c0da1..d0aa41c 100644 --- a/src/DotNetCore.CAP/Models/CapQueue.cs +++ b/src/DotNetCore.CAP/Models/CapQueue.cs @@ -9,4 +9,4 @@ /// public MessageType MessageType { get; set; } } -} +} \ No newline at end of file diff --git a/src/DotNetCore.CAP/Models/MessageType.cs b/src/DotNetCore.CAP/Models/MessageType.cs index 1ddfc74..5097962 100644 --- a/src/DotNetCore.CAP/Models/MessageType.cs +++ b/src/DotNetCore.CAP/Models/MessageType.cs @@ -5,4 +5,4 @@ Publish, Subscribe } -} +} \ No newline at end of file diff --git a/src/DotNetCore.CAP/OperateResult.cs b/src/DotNetCore.CAP/OperateResult.cs index 41fcc33..04aa787 100644 --- a/src/DotNetCore.CAP/OperateResult.cs +++ b/src/DotNetCore.CAP/OperateResult.cs @@ -32,7 +32,7 @@ namespace DotNetCore.CAP /// Returns an indicating a successful identity operation. /// /// An indicating a successful operation. - public static OperateResult Success { get; } = new OperateResult {Succeeded = true}; + public static OperateResult Success { get; } = new OperateResult { Succeeded = true }; /// /// Creates an indicating a failed operation, with a list of if applicable. @@ -41,7 +41,7 @@ namespace DotNetCore.CAP /// An indicating a failed operation, with a list of if applicable. public static OperateResult Failed(params OperateError[] errors) { - var result = new OperateResult {Succeeded = false}; + var result = new OperateResult { Succeeded = false }; if (errors != null) { result._errors.AddRange(errors); diff --git a/src/DotNetCore.CAP/Processor/IAdditionalProcessor.cs b/src/DotNetCore.CAP/Processor/IAdditionalProcessor.cs index 9c414ff..b678614 100644 --- a/src/DotNetCore.CAP/Processor/IAdditionalProcessor.cs +++ b/src/DotNetCore.CAP/Processor/IAdditionalProcessor.cs @@ -1,11 +1,6 @@ -using System; -using System.Collections.Generic; -using System.Text; - -namespace DotNetCore.CAP.Processor +namespace DotNetCore.CAP.Processor { public interface IAdditionalProcessor : IProcessor { - } -} +} \ No newline at end of file diff --git a/src/DotNetCore.CAP/Processor/IDispatcher.Default.cs b/src/DotNetCore.CAP/Processor/IDispatcher.Default.cs index 1066ddf..53a0a73 100644 --- a/src/DotNetCore.CAP/Processor/IDispatcher.Default.cs +++ b/src/DotNetCore.CAP/Processor/IDispatcher.Default.cs @@ -93,4 +93,4 @@ namespace DotNetCore.CAP.Processor return fetched != null; } } -} +} \ No newline at end of file diff --git a/src/DotNetCore.CAP/Processor/IDispatcher.cs b/src/DotNetCore.CAP/Processor/IDispatcher.cs index f358ac6..f612d02 100644 --- a/src/DotNetCore.CAP/Processor/IDispatcher.cs +++ b/src/DotNetCore.CAP/Processor/IDispatcher.cs @@ -1,11 +1,7 @@ -using System; -using System.Collections.Generic; -using System.Text; - -namespace DotNetCore.CAP.Processor +namespace DotNetCore.CAP.Processor { public interface IDispatcher : IProcessor { bool Waiting { get; } } -} +} \ No newline at end of file diff --git a/src/DotNetCore.CAP/Processor/IProcessor.PublishQueuer.cs b/src/DotNetCore.CAP/Processor/IProcessor.PublishQueuer.cs index ec0faf3..4537c17 100644 --- a/src/DotNetCore.CAP/Processor/IProcessor.PublishQueuer.cs +++ b/src/DotNetCore.CAP/Processor/IProcessor.PublishQueuer.cs @@ -2,67 +2,67 @@ using System.Threading; using System.Threading.Tasks; using DotNetCore.CAP.Infrastructure; -using DotNetCore.CAP.Processor.States; using DotNetCore.CAP.Models; +using DotNetCore.CAP.Processor.States; using Microsoft.Extensions.DependencyInjection; using Microsoft.Extensions.Logging; using Microsoft.Extensions.Options; namespace DotNetCore.CAP.Processor { - public class PublishQueuer : IProcessor + public class PublishQueuer : IProcessor { - private ILogger _logger; - private CapOptions _options; - private IStateChanger _stateChanger; - private IServiceProvider _provider; - private TimeSpan _pollingDelay; + private ILogger _logger; + private CapOptions _options; + private IStateChanger _stateChanger; + private IServiceProvider _provider; + private TimeSpan _pollingDelay; public static readonly AutoResetEvent PulseEvent = new AutoResetEvent(true); public PublishQueuer( - ILogger logger, - IOptions options, - IStateChanger stateChanger, - IServiceProvider provider) - { - _logger = logger; - _options = options.Value; - _stateChanger = stateChanger; - _provider = provider; + ILogger logger, + IOptions options, + IStateChanger stateChanger, + IServiceProvider provider) + { + _logger = logger; + _options = options.Value; + _stateChanger = stateChanger; + _provider = provider; - _pollingDelay = TimeSpan.FromSeconds(_options.PollingDelay); - } + _pollingDelay = TimeSpan.FromSeconds(_options.PollingDelay); + } - public async Task ProcessAsync(ProcessingContext context) - { - using (var scope = _provider.CreateScope()) - { + public async Task ProcessAsync(ProcessingContext context) + { + using (var scope = _provider.CreateScope()) + { CapPublishedMessage sentMessage; - var provider = scope.ServiceProvider; - var connection = provider.GetRequiredService(); + var provider = scope.ServiceProvider; + var connection = provider.GetRequiredService(); - while ( - !context.IsStopping && - (sentMessage = await connection.GetNextPublishedMessageToBeEnqueuedAsync()) != null) + while ( + !context.IsStopping && + (sentMessage = await connection.GetNextPublishedMessageToBeEnqueuedAsync()) != null) { var state = new EnqueuedState(); - using (var transaction = connection.CreateTransaction()) - { - _stateChanger.ChangeState(sentMessage, state, transaction); - await transaction.CommitAsync(); - } - } - } + using (var transaction = connection.CreateTransaction()) + { + _stateChanger.ChangeState(sentMessage, state, transaction); + await transaction.CommitAsync(); + } + } + } context.ThrowIfStopping(); - + DefaultDispatcher.PulseEvent.Set(); await WaitHandleEx.WaitAnyAsync(PulseEvent, context.CancellationToken.WaitHandle, _pollingDelay); - } - } -} + } + } +} \ No newline at end of file diff --git a/src/DotNetCore.CAP/Processor/IProcessor.SubscribeQueuer.cs b/src/DotNetCore.CAP/Processor/IProcessor.SubscribeQueuer.cs index 17c2425..4a85fb0 100644 --- a/src/DotNetCore.CAP/Processor/IProcessor.SubscribeQueuer.cs +++ b/src/DotNetCore.CAP/Processor/IProcessor.SubscribeQueuer.cs @@ -2,8 +2,8 @@ using System.Threading; using System.Threading.Tasks; using DotNetCore.CAP.Infrastructure; -using DotNetCore.CAP.Processor.States; using DotNetCore.CAP.Models; +using DotNetCore.CAP.Processor.States; using Microsoft.Extensions.DependencyInjection; using Microsoft.Extensions.Logging; using Microsoft.Extensions.Options; @@ -65,4 +65,4 @@ namespace DotNetCore.CAP.Processor context.CancellationToken.WaitHandle, _pollingDelay); } } -} +} \ No newline at end of file diff --git a/src/DotNetCore.CAP/Processor/RetryBehavior.cs b/src/DotNetCore.CAP/Processor/RetryBehavior.cs index 04cb667..1421fae 100644 --- a/src/DotNetCore.CAP/Processor/RetryBehavior.cs +++ b/src/DotNetCore.CAP/Processor/RetryBehavior.cs @@ -18,7 +18,7 @@ namespace DotNetCore.CAP.Processor { DefaultRetryCount = 25; DefaultRetryInThunk = retries => - (int) Math.Round(Math.Pow(retries - 1, 4) + 15 + (_random.Next(30) * (retries))); + (int)Math.Round(Math.Pow(retries - 1, 4) + 15 + (_random.Next(30) * (retries))); DefaultRetry = new RetryBehavior(true); NoRetry = new RetryBehavior(false); diff --git a/src/DotNetCore.CAP/QueueExecutorFactory.cs b/src/DotNetCore.CAP/QueueExecutorFactory.cs index 1c71e93..7790167 100644 --- a/src/DotNetCore.CAP/QueueExecutorFactory.cs +++ b/src/DotNetCore.CAP/QueueExecutorFactory.cs @@ -18,8 +18,8 @@ namespace DotNetCore.CAP public IQueueExecutor GetInstance(MessageType messageType) { var _queueExectors = _serviceProvider.GetServices(); - - if (messageType== MessageType.Publish) + + if (messageType == MessageType.Publish) { return _queueExectors.FirstOrDefault(x => typeof(BasePublishQueueExecutor).IsAssignableFrom(x.GetType())); } @@ -29,4 +29,4 @@ namespace DotNetCore.CAP } } } -} +} \ No newline at end of file From 228495568de44b9f3df47dc26583b184bf9070a1 Mon Sep 17 00:00:00 2001 From: yangxiaodong Date: Mon, 17 Jul 2017 11:28:46 +0800 Subject: [PATCH 28/68] cleanup code. --- .../{CapSubscribeAttribute.cs => CAP.SubscribeAttribute.cs} | 3 ++- .../{CapSubscribeAttribute.cs => CAP.SubscribeAttribute.cs} | 3 ++- 2 files changed, 4 insertions(+), 2 deletions(-) rename src/DotNetCore.CAP.Kafka/{CapSubscribeAttribute.cs => CAP.SubscribeAttribute.cs} (93%) rename src/DotNetCore.CAP.RabbitMQ/{CapSubscribeAttribute.cs => CAP.SubscribeAttribute.cs} (74%) diff --git a/src/DotNetCore.CAP.Kafka/CapSubscribeAttribute.cs b/src/DotNetCore.CAP.Kafka/CAP.SubscribeAttribute.cs similarity index 93% rename from src/DotNetCore.CAP.Kafka/CapSubscribeAttribute.cs rename to src/DotNetCore.CAP.Kafka/CAP.SubscribeAttribute.cs index 92b2a93..a914df6 100644 --- a/src/DotNetCore.CAP.Kafka/CapSubscribeAttribute.cs +++ b/src/DotNetCore.CAP.Kafka/CAP.SubscribeAttribute.cs @@ -1,6 +1,7 @@ using DotNetCore.CAP.Abstractions; -namespace DotNetCore.CAP.Kafka +// ReSharper disable once CheckNamespace +namespace DotNetCore.CAP { public class CapSubscribeAttribute : TopicAttribute { diff --git a/src/DotNetCore.CAP.RabbitMQ/CapSubscribeAttribute.cs b/src/DotNetCore.CAP.RabbitMQ/CAP.SubscribeAttribute.cs similarity index 74% rename from src/DotNetCore.CAP.RabbitMQ/CapSubscribeAttribute.cs rename to src/DotNetCore.CAP.RabbitMQ/CAP.SubscribeAttribute.cs index de63ac7..92fb295 100644 --- a/src/DotNetCore.CAP.RabbitMQ/CapSubscribeAttribute.cs +++ b/src/DotNetCore.CAP.RabbitMQ/CAP.SubscribeAttribute.cs @@ -1,6 +1,7 @@ using DotNetCore.CAP.Abstractions; -namespace DotNetCore.CAP.RabbitMQ +// ReSharper disable once CheckNamespace +namespace DotNetCore.CAP { public class CapSubscribeAttribute : TopicAttribute { From 90f14f6562466287222dfd1c673c82c3793ade7d Mon Sep 17 00:00:00 2001 From: yangxiaodong Date: Mon, 17 Jul 2017 11:28:56 +0800 Subject: [PATCH 29/68] cleanup code. --- .../CAP.EFOptions.cs | 1 + .../CAP.Options.Extensions.cs | 1 + .../CAP.SqlServerCapOptionsExtension.cs | 3 ++- .../CAP.SqlServerOptions.cs | 5 ++-- .../SqlServerFetchedMessage.cs | 1 + .../SqlServerStorage.cs | 8 +++---- .../SqlServerStorageConnection.cs | 4 +--- .../SqlServerStorageTransaction.cs | 13 ++++------ .../CAP.KafkaCapOptionsExtension.cs | 5 ++-- src/DotNetCore.CAP.Kafka/CAP.KafkaOptions.cs | 1 + .../CAP.Options.Extensions.cs | 1 + .../CAP.Options.Extensions.cs | 1 + .../CAP.RabbiMQOptions.cs | 5 ++-- .../CAP.RabbitMQCapOptionsExtension.cs | 3 ++- .../PublishQueueExecutor.cs | 24 +++++++++---------- .../RabbitMQConsumerClient.cs | 2 +- .../IQueueExecutor.Publish.Base.cs | 2 +- src/DotNetCore.CAP/IQueueExecutor.Subscibe.cs | 3 ++- src/DotNetCore.CAP/QueueExecutorFactory.cs | 13 ++++------ 19 files changed, 49 insertions(+), 47 deletions(-) diff --git a/src/DotNetCore.CAP.EntityFrameworkCore/CAP.EFOptions.cs b/src/DotNetCore.CAP.EntityFrameworkCore/CAP.EFOptions.cs index a742b2a..68aa524 100644 --- a/src/DotNetCore.CAP.EntityFrameworkCore/CAP.EFOptions.cs +++ b/src/DotNetCore.CAP.EntityFrameworkCore/CAP.EFOptions.cs @@ -1,5 +1,6 @@ using System; +// ReSharper disable once CheckNamespace namespace DotNetCore.CAP { public class EFOptions diff --git a/src/DotNetCore.CAP.EntityFrameworkCore/CAP.Options.Extensions.cs b/src/DotNetCore.CAP.EntityFrameworkCore/CAP.Options.Extensions.cs index 1f2f807..0c1b6f8 100644 --- a/src/DotNetCore.CAP.EntityFrameworkCore/CAP.Options.Extensions.cs +++ b/src/DotNetCore.CAP.EntityFrameworkCore/CAP.Options.Extensions.cs @@ -2,6 +2,7 @@ using DotNetCore.CAP; using Microsoft.EntityFrameworkCore; +// ReSharper disable once CheckNamespace namespace Microsoft.Extensions.DependencyInjection { public static class CapOptionsExtensions diff --git a/src/DotNetCore.CAP.EntityFrameworkCore/CAP.SqlServerCapOptionsExtension.cs b/src/DotNetCore.CAP.EntityFrameworkCore/CAP.SqlServerCapOptionsExtension.cs index 8f60f34..204cc49 100644 --- a/src/DotNetCore.CAP.EntityFrameworkCore/CAP.SqlServerCapOptionsExtension.cs +++ b/src/DotNetCore.CAP.EntityFrameworkCore/CAP.SqlServerCapOptionsExtension.cs @@ -3,11 +3,12 @@ using DotNetCore.CAP.EntityFrameworkCore; using DotNetCore.CAP.Processor; using Microsoft.Extensions.DependencyInjection; +// ReSharper disable once CheckNamespace namespace DotNetCore.CAP { public class SqlServerCapOptionsExtension : ICapOptionsExtension { - private Action _configure; + private readonly Action _configure; public SqlServerCapOptionsExtension(Action configure) { diff --git a/src/DotNetCore.CAP.EntityFrameworkCore/CAP.SqlServerOptions.cs b/src/DotNetCore.CAP.EntityFrameworkCore/CAP.SqlServerOptions.cs index 40a2d4f..a0f3fa2 100644 --- a/src/DotNetCore.CAP.EntityFrameworkCore/CAP.SqlServerOptions.cs +++ b/src/DotNetCore.CAP.EntityFrameworkCore/CAP.SqlServerOptions.cs @@ -1,10 +1,11 @@ -namespace DotNetCore.CAP +// ReSharper disable once CheckNamespace +namespace DotNetCore.CAP { public class SqlServerOptions : EFOptions { /// /// Gets or sets the database's connection string that will be used to store database entities. /// - public string ConnectionString { get; set; } //= "Server=DESKTOP-M9R8T31;Initial Catalog=Test;User Id=sa;Password=P@ssw0rd;MultipleActiveResultSets=True"; + public string ConnectionString { get; set; } } } \ No newline at end of file diff --git a/src/DotNetCore.CAP.EntityFrameworkCore/SqlServerFetchedMessage.cs b/src/DotNetCore.CAP.EntityFrameworkCore/SqlServerFetchedMessage.cs index e93167d..6e9d8e2 100644 --- a/src/DotNetCore.CAP.EntityFrameworkCore/SqlServerFetchedMessage.cs +++ b/src/DotNetCore.CAP.EntityFrameworkCore/SqlServerFetchedMessage.cs @@ -66,6 +66,7 @@ namespace DotNetCore.CAP.EntityFrameworkCore } catch { + // ignored } } } diff --git a/src/DotNetCore.CAP.EntityFrameworkCore/SqlServerStorage.cs b/src/DotNetCore.CAP.EntityFrameworkCore/SqlServerStorage.cs index b5b73bb..8be57eb 100644 --- a/src/DotNetCore.CAP.EntityFrameworkCore/SqlServerStorage.cs +++ b/src/DotNetCore.CAP.EntityFrameworkCore/SqlServerStorage.cs @@ -11,8 +11,8 @@ namespace DotNetCore.CAP.EntityFrameworkCore { public class SqlServerStorage : IStorage { - private IServiceProvider _provider; - private ILogger _logger; + private readonly IServiceProvider _provider; + private readonly ILogger _logger; public SqlServerStorage( IServiceProvider provider, @@ -43,7 +43,7 @@ namespace DotNetCore.CAP.EntityFrameworkCore protected virtual string CreateDbTablesScript(string schema) { - var batchSQL = + var batchSql = $@" IF NOT EXISTS (SELECT * FROM sys.schemas WHERE name = '{schema}') BEGIN @@ -96,7 +96,7 @@ CREATE TABLE [{schema}].[Published]( ) ON [PRIMARY] TEXTIMAGE_ON [PRIMARY] END GO"; - return batchSQL; + return batchSql; } } } \ No newline at end of file diff --git a/src/DotNetCore.CAP.EntityFrameworkCore/SqlServerStorageConnection.cs b/src/DotNetCore.CAP.EntityFrameworkCore/SqlServerStorageConnection.cs index 96929c6..eee5ac7 100644 --- a/src/DotNetCore.CAP.EntityFrameworkCore/SqlServerStorageConnection.cs +++ b/src/DotNetCore.CAP.EntityFrameworkCore/SqlServerStorageConnection.cs @@ -95,15 +95,13 @@ VALUES(@Name,@Group,@Content,@Retries,@Added,@ExpiresAt,@StatusName);"; private async Task FetchNextMessageCoreAsync(string sql, object args = null) { - FetchedMessage fetched = null; - using (var connection = new SqlConnection(_options.ConnectionString)) { using (var transaction = connection.BeginTransaction(IsolationLevel.ReadCommitted)) { try { - fetched = await connection.QueryFirstOrDefaultAsync(sql, args, transaction); + var fetched = await connection.QueryFirstOrDefaultAsync(sql, args, transaction); if (fetched == null) return null; diff --git a/src/DotNetCore.CAP.EntityFrameworkCore/SqlServerStorageTransaction.cs b/src/DotNetCore.CAP.EntityFrameworkCore/SqlServerStorageTransaction.cs index e0cdcf3..81dd805 100644 --- a/src/DotNetCore.CAP.EntityFrameworkCore/SqlServerStorageTransaction.cs +++ b/src/DotNetCore.CAP.EntityFrameworkCore/SqlServerStorageTransaction.cs @@ -9,20 +9,17 @@ namespace DotNetCore.CAP.EntityFrameworkCore { public class SqlServerStorageTransaction : IStorageTransaction, IDisposable { - private readonly SqlServerStorageConnection _connection; - private readonly SqlServerOptions _options; private readonly string _schema; - private IDbTransaction _dbTransaction; - private IDbConnection _dbConnection; + private readonly IDbTransaction _dbTransaction; + private readonly IDbConnection _dbConnection; public SqlServerStorageTransaction(SqlServerStorageConnection connection) { - _connection = connection; - _options = _connection.Options; - _schema = _options.Schema; + var options = connection.Options; + _schema = options.Schema; - _dbConnection = new SqlConnection(_options.ConnectionString); + _dbConnection = new SqlConnection(options.ConnectionString); _dbTransaction = _dbConnection.BeginTransaction(IsolationLevel.ReadCommitted); } diff --git a/src/DotNetCore.CAP.Kafka/CAP.KafkaCapOptionsExtension.cs b/src/DotNetCore.CAP.Kafka/CAP.KafkaCapOptionsExtension.cs index 42df3f8..2dbf888 100644 --- a/src/DotNetCore.CAP.Kafka/CAP.KafkaCapOptionsExtension.cs +++ b/src/DotNetCore.CAP.Kafka/CAP.KafkaCapOptionsExtension.cs @@ -2,11 +2,12 @@ using DotNetCore.CAP.Kafka; using Microsoft.Extensions.DependencyInjection; +// ReSharper disable once CheckNamespace namespace DotNetCore.CAP { public class KafkaCapOptionsExtension : ICapOptionsExtension { - private Action _configure; + private readonly Action _configure; public KafkaCapOptionsExtension(Action configure) { @@ -20,7 +21,7 @@ namespace DotNetCore.CAP var kafkaOptions = new KafkaOptions(); _configure(kafkaOptions); services.AddSingleton(kafkaOptions); - + services.AddSingleton(); services.AddTransient(); } diff --git a/src/DotNetCore.CAP.Kafka/CAP.KafkaOptions.cs b/src/DotNetCore.CAP.Kafka/CAP.KafkaOptions.cs index 55b055b..34cf92d 100644 --- a/src/DotNetCore.CAP.Kafka/CAP.KafkaOptions.cs +++ b/src/DotNetCore.CAP.Kafka/CAP.KafkaOptions.cs @@ -2,6 +2,7 @@ using System.Collections.Generic; using System.Linq; +// ReSharper disable once CheckNamespace namespace DotNetCore.CAP { /// diff --git a/src/DotNetCore.CAP.Kafka/CAP.Options.Extensions.cs b/src/DotNetCore.CAP.Kafka/CAP.Options.Extensions.cs index c562251..65314f4 100644 --- a/src/DotNetCore.CAP.Kafka/CAP.Options.Extensions.cs +++ b/src/DotNetCore.CAP.Kafka/CAP.Options.Extensions.cs @@ -1,6 +1,7 @@ using System; using DotNetCore.CAP; +// ReSharper disable once CheckNamespace namespace Microsoft.Extensions.DependencyInjection { public static class CapOptionsExtensions diff --git a/src/DotNetCore.CAP.RabbitMQ/CAP.Options.Extensions.cs b/src/DotNetCore.CAP.RabbitMQ/CAP.Options.Extensions.cs index 9320be4..4d59112 100644 --- a/src/DotNetCore.CAP.RabbitMQ/CAP.Options.Extensions.cs +++ b/src/DotNetCore.CAP.RabbitMQ/CAP.Options.Extensions.cs @@ -1,6 +1,7 @@ using System; using DotNetCore.CAP; +// ReSharper disable once CheckNamespace namespace Microsoft.Extensions.DependencyInjection { public static class CapOptionsExtensions diff --git a/src/DotNetCore.CAP.RabbitMQ/CAP.RabbiMQOptions.cs b/src/DotNetCore.CAP.RabbitMQ/CAP.RabbiMQOptions.cs index ddce147..09a90ef 100644 --- a/src/DotNetCore.CAP.RabbitMQ/CAP.RabbiMQOptions.cs +++ b/src/DotNetCore.CAP.RabbitMQ/CAP.RabbiMQOptions.cs @@ -1,4 +1,5 @@ -namespace DotNetCore.CAP +// ReSharper disable once CheckNamespace +namespace DotNetCore.CAP { public class RabbitMQOptions { @@ -34,7 +35,7 @@ public string HostName { get; set; } = "localhost"; /// The topic exchange type. - internal string EXCHANGE_TYPE = "topic"; + internal const string ExchangeType = "topic"; /// /// Password to use when authenticating to the server. diff --git a/src/DotNetCore.CAP.RabbitMQ/CAP.RabbitMQCapOptionsExtension.cs b/src/DotNetCore.CAP.RabbitMQ/CAP.RabbitMQCapOptionsExtension.cs index ee677c8..14eedbb 100644 --- a/src/DotNetCore.CAP.RabbitMQ/CAP.RabbitMQCapOptionsExtension.cs +++ b/src/DotNetCore.CAP.RabbitMQ/CAP.RabbitMQCapOptionsExtension.cs @@ -2,11 +2,12 @@ using DotNetCore.CAP.RabbitMQ; using Microsoft.Extensions.DependencyInjection; +// ReSharper disable once CheckNamespace namespace DotNetCore.CAP { public class RabbitMQCapOptionsExtension : ICapOptionsExtension { - private Action _configure; + private readonly Action _configure; public RabbitMQCapOptionsExtension(Action configure) { diff --git a/src/DotNetCore.CAP.RabbitMQ/PublishQueueExecutor.cs b/src/DotNetCore.CAP.RabbitMQ/PublishQueueExecutor.cs index 80f0cfb..3e439e2 100644 --- a/src/DotNetCore.CAP.RabbitMQ/PublishQueueExecutor.cs +++ b/src/DotNetCore.CAP.RabbitMQ/PublishQueueExecutor.cs @@ -11,7 +11,7 @@ namespace DotNetCore.CAP.RabbitMQ public class PublishQueueExecutor : BasePublishQueueExecutor { private readonly ILogger _logger; - private readonly RabbitMQOptions _rabbitMqOptions; + private readonly RabbitMQOptions _rabbitMQOptions; public PublishQueueExecutor(IStateChanger stateChanger, IOptions options, @@ -19,21 +19,21 @@ namespace DotNetCore.CAP.RabbitMQ : base(stateChanger, logger) { _logger = logger; - _rabbitMqOptions = options.Value; + _rabbitMQOptions = options.Value; } public override Task PublishAsync(string keyName, string content) { var factory = new ConnectionFactory() { - HostName = _rabbitMqOptions.HostName, - UserName = _rabbitMqOptions.UserName, - Port = _rabbitMqOptions.Port, - Password = _rabbitMqOptions.Password, - VirtualHost = _rabbitMqOptions.VirtualHost, - RequestedConnectionTimeout = _rabbitMqOptions.RequestedConnectionTimeout, - SocketReadTimeout = _rabbitMqOptions.SocketReadTimeout, - SocketWriteTimeout = _rabbitMqOptions.SocketWriteTimeout + HostName = _rabbitMQOptions.HostName, + UserName = _rabbitMQOptions.UserName, + Port = _rabbitMQOptions.Port, + Password = _rabbitMQOptions.Password, + VirtualHost = _rabbitMQOptions.VirtualHost, + RequestedConnectionTimeout = _rabbitMQOptions.RequestedConnectionTimeout, + SocketReadTimeout = _rabbitMQOptions.SocketReadTimeout, + SocketWriteTimeout = _rabbitMQOptions.SocketWriteTimeout }; try @@ -43,8 +43,8 @@ namespace DotNetCore.CAP.RabbitMQ { var body = Encoding.UTF8.GetBytes(content); - channel.ExchangeDeclare(_rabbitMqOptions.TopicExchangeName, _rabbitMqOptions.EXCHANGE_TYPE); - channel.BasicPublish(exchange: _rabbitMqOptions.TopicExchangeName, + channel.ExchangeDeclare(_rabbitMQOptions.TopicExchangeName, RabbitMQOptions.ExchangeType); + channel.BasicPublish(exchange: _rabbitMQOptions.TopicExchangeName, routingKey: keyName, basicProperties: null, body: body); diff --git a/src/DotNetCore.CAP.RabbitMQ/RabbitMQConsumerClient.cs b/src/DotNetCore.CAP.RabbitMQ/RabbitMQConsumerClient.cs index 9ca8a86..7e19de1 100644 --- a/src/DotNetCore.CAP.RabbitMQ/RabbitMQConsumerClient.cs +++ b/src/DotNetCore.CAP.RabbitMQ/RabbitMQConsumerClient.cs @@ -46,7 +46,7 @@ namespace DotNetCore.CAP.RabbitMQ _connection = _connectionFactory.CreateConnection(); _channel = _connection.CreateModel(); - _channel.ExchangeDeclare(exchange: _exchageName, type: _rabbitMQOptions.EXCHANGE_TYPE); + _channel.ExchangeDeclare(exchange: _exchageName, type: _rabbitMQOptions.ExchangeType); _channel.QueueDeclare(_queueName, exclusive: false); } diff --git a/src/DotNetCore.CAP/IQueueExecutor.Publish.Base.cs b/src/DotNetCore.CAP/IQueueExecutor.Publish.Base.cs index 074fd66..10fd2eb 100644 --- a/src/DotNetCore.CAP/IQueueExecutor.Publish.Base.cs +++ b/src/DotNetCore.CAP/IQueueExecutor.Publish.Base.cs @@ -13,7 +13,7 @@ namespace DotNetCore.CAP private readonly IStateChanger _stateChanger; private readonly ILogger _logger; - public BasePublishQueueExecutor(IStateChanger stateChanger, + protected BasePublishQueueExecutor(IStateChanger stateChanger, ILogger logger) { _stateChanger = stateChanger; diff --git a/src/DotNetCore.CAP/IQueueExecutor.Subscibe.cs b/src/DotNetCore.CAP/IQueueExecutor.Subscibe.cs index e771455..503f2f3 100644 --- a/src/DotNetCore.CAP/IQueueExecutor.Subscibe.cs +++ b/src/DotNetCore.CAP/IQueueExecutor.Subscibe.cs @@ -116,7 +116,8 @@ namespace DotNetCore.CAP } catch (SubscriberNotFoundException ex) { - throw ex; + _logger.LogError("Can not be found subscribe method of name: " + receivedMessage.Name); + return OperateResult.Failed(ex); } catch (Exception ex) { diff --git a/src/DotNetCore.CAP/QueueExecutorFactory.cs b/src/DotNetCore.CAP/QueueExecutorFactory.cs index 7790167..3e84684 100644 --- a/src/DotNetCore.CAP/QueueExecutorFactory.cs +++ b/src/DotNetCore.CAP/QueueExecutorFactory.cs @@ -17,16 +17,11 @@ namespace DotNetCore.CAP public IQueueExecutor GetInstance(MessageType messageType) { - var _queueExectors = _serviceProvider.GetServices(); + var queueExectors = _serviceProvider.GetServices(); - if (messageType == MessageType.Publish) - { - return _queueExectors.FirstOrDefault(x => typeof(BasePublishQueueExecutor).IsAssignableFrom(x.GetType())); - } - else - { - return _queueExectors.FirstOrDefault(x => !typeof(BasePublishQueueExecutor).IsAssignableFrom(x.GetType())); - } + return messageType == MessageType.Publish + ? queueExectors.FirstOrDefault(x => x is BasePublishQueueExecutor) + : queueExectors.FirstOrDefault(x => !(x is BasePublishQueueExecutor)); } } } \ No newline at end of file From a3d26ab70e885ca7ee943f8cb769968acf2d964d Mon Sep 17 00:00:00 2001 From: yangxiaodong Date: Mon, 17 Jul 2017 13:27:00 +0800 Subject: [PATCH 30/68] rename parameter --- .../CapPublisher.cs | 34 +++++++++---------- 1 file changed, 17 insertions(+), 17 deletions(-) diff --git a/src/DotNetCore.CAP.EntityFrameworkCore/CapPublisher.cs b/src/DotNetCore.CAP.EntityFrameworkCore/CapPublisher.cs index 13a8700..e90bdad 100644 --- a/src/DotNetCore.CAP.EntityFrameworkCore/CapPublisher.cs +++ b/src/DotNetCore.CAP.EntityFrameworkCore/CapPublisher.cs @@ -30,64 +30,64 @@ namespace DotNetCore.CAP.EntityFrameworkCore } } - public Task PublishAsync(string topic, string content) + public Task PublishAsync(string name, string content) { - if (topic == null) throw new ArgumentNullException(nameof(topic)); + if (name == null) throw new ArgumentNullException(nameof(name)); if (!IsUsingEF) throw new InvalidOperationException("If you are using the EntityFramework, you need to configure the DbContextType first." + " otherwise you need to use overloaded method with IDbConnection and IDbTransaction."); - return Publish(topic, content); + return Publish(name, content); } - public Task PublishAsync(string topic, T contentObj) + public Task PublishAsync(string name, T contentObj) { - if (topic == null) throw new ArgumentNullException(nameof(topic)); + if (name == null) throw new ArgumentNullException(nameof(name)); if (!IsUsingEF) throw new InvalidOperationException("If you are using the EntityFramework, you need to configure the DbContextType first." + " otherwise you need to use overloaded method with IDbConnection and IDbTransaction."); var content = Helper.ToJson(contentObj); - return Publish(topic, content); + return Publish(name, content); } - public Task PublishAsync(string topic, string content, IDbConnection dbConnection) + public Task PublishAsync(string name, string content, IDbConnection dbConnection) { if (IsUsingEF) throw new InvalidOperationException("If you are using the EntityFramework, you do not need to use this overloaded."); - if (topic == null) throw new ArgumentNullException(nameof(topic)); + if (name == null) throw new ArgumentNullException(nameof(name)); if (dbConnection == null) throw new ArgumentNullException(nameof(dbConnection)); var dbTransaction = dbConnection.BeginTransaction(IsolationLevel.ReadCommitted); - return PublishWithTrans(topic, content, dbConnection, dbTransaction); + return PublishWithTrans(name, content, dbConnection, dbTransaction); } - public Task PublishAsync(string topic, string content, IDbConnection dbConnection, IDbTransaction dbTransaction) + public Task PublishAsync(string name, string content, IDbConnection dbConnection, IDbTransaction dbTransaction) { if (IsUsingEF) throw new InvalidOperationException("If you are using the EntityFramework, you do not need to use this overloaded."); - if (topic == null) throw new ArgumentNullException(nameof(topic)); + if (name == null) throw new ArgumentNullException(nameof(name)); if (dbConnection == null) throw new ArgumentNullException(nameof(dbConnection)); if (dbTransaction == null) throw new ArgumentNullException(nameof(dbTransaction)); - return PublishWithTrans(topic, content, dbConnection, dbTransaction); + return PublishWithTrans(name, content, dbConnection, dbTransaction); } - private async Task Publish(string topic, string content) + private async Task Publish(string name, string content) { var connection = _dbContext.Database.GetDbConnection(); var transaction = _dbContext.Database.CurrentTransaction; transaction = transaction ?? await _dbContext.Database.BeginTransactionAsync(IsolationLevel.ReadCommitted); var dbTransaction = transaction.GetDbTransaction(); - await PublishWithTrans(topic, content, connection, dbTransaction); + await PublishWithTrans(name, content, connection, dbTransaction); } - private async Task PublishWithTrans(string topic, string content, IDbConnection dbConnection, IDbTransaction dbTransaction) + private async Task PublishWithTrans(string name, string content, IDbConnection dbConnection, IDbTransaction dbTransaction) { var message = new CapPublishedMessage { - Name = topic, + Name = name, Content = content, StatusName = StatusName.Scheduled }; - var sql = $"INSERT INTO {_options.Schema}.[Published] ([Id],[Added],[Content],[KeyName],[ExpiresAt],[Retries],[StatusName])VALUES(@Id,@Added,@Content,@KeyName,@ExpiresAt,@Retries,@StatusName)"; + var sql = $"INSERT INTO {_options.Schema}.[Published] ([Name],[Content],[Retries],[Added],[ExpiresAt],[StatusName])VALUES(@Name,@Content,@Retries,@Added,@ExpiresAt,@StatusName)"; await dbConnection.ExecuteAsync(sql, message, transaction: dbTransaction); PublishQueuer.PulseEvent.Set(); From 055bf94b1977f3275e0dfdb390bf0a87a67e4339 Mon Sep 17 00:00:00 2001 From: yangxiaodong Date: Mon, 17 Jul 2017 13:28:33 +0800 Subject: [PATCH 31/68] update batchsql scripts. --- .../SqlServerStorage.cs | 41 +++++++------------ 1 file changed, 14 insertions(+), 27 deletions(-) diff --git a/src/DotNetCore.CAP.EntityFrameworkCore/SqlServerStorage.cs b/src/DotNetCore.CAP.EntityFrameworkCore/SqlServerStorage.cs index 8be57eb..765d88f 100644 --- a/src/DotNetCore.CAP.EntityFrameworkCore/SqlServerStorage.cs +++ b/src/DotNetCore.CAP.EntityFrameworkCore/SqlServerStorage.cs @@ -4,52 +4,42 @@ using System.Threading; using System.Threading.Tasks; using Dapper; using Microsoft.EntityFrameworkCore; -using Microsoft.Extensions.DependencyInjection; using Microsoft.Extensions.Logging; namespace DotNetCore.CAP.EntityFrameworkCore { public class SqlServerStorage : IStorage { - private readonly IServiceProvider _provider; + private readonly SqlServerOptions _options; private readonly ILogger _logger; - public SqlServerStorage( - IServiceProvider provider, - ILogger logger) + public SqlServerStorage(ILogger logger, SqlServerOptions options) { - _provider = provider; + _options = options; _logger = logger; } public async Task InitializeAsync(CancellationToken cancellationToken) { - using (var scope = _provider.CreateScope()) - { - if (cancellationToken.IsCancellationRequested) return; - - var provider = scope.ServiceProvider; - var options = provider.GetRequiredService(); + if (cancellationToken.IsCancellationRequested) return; - var sql = CreateDbTablesScript(options.Schema); + var sql = CreateDbTablesScript(_options.Schema); - using (var connection = new SqlConnection(options.ConnectionString)) - { - await connection.ExecuteAsync(sql); - } - _logger.LogDebug("Ensuring all create database tables script are applied."); + using (var connection = new SqlConnection(_options.ConnectionString)) + { + await connection.ExecuteAsync(sql); } + _logger.LogDebug("Ensuring all create database tables script are applied."); } protected virtual string CreateDbTablesScript(string schema) { var batchSql = -$@" + $@" IF NOT EXISTS (SELECT * FROM sys.schemas WHERE name = '{schema}') BEGIN EXEC('CREATE SCHEMA {schema}') -END -GO +END; IF OBJECT_ID(N'[{schema}].[Queue]',N'U') IS NULL BEGIN @@ -57,8 +47,7 @@ BEGIN [MessageId] [int] NOT NULL, [MessageType] [tinyint] NOT NULL ) ON [PRIMARY] -END -GO +END; IF OBJECT_ID(N'[{schema}].[Received]',N'U') IS NULL BEGIN @@ -76,8 +65,7 @@ CREATE TABLE [{schema}].[Received]( [Id] ASC )WITH (PAD_INDEX = OFF, STATISTICS_NORECOMPUTE = OFF, IGNORE_DUP_KEY = OFF, ALLOW_ROW_LOCKS = ON, ALLOW_PAGE_LOCKS = ON) ON [PRIMARY] ) ON [PRIMARY] TEXTIMAGE_ON [PRIMARY] -END -GO +END; IF OBJECT_ID(N'[{schema}].[Published]',N'U') IS NULL BEGIN @@ -94,8 +82,7 @@ CREATE TABLE [{schema}].[Published]( [Id] ASC )WITH (PAD_INDEX = OFF, STATISTICS_NORECOMPUTE = OFF, IGNORE_DUP_KEY = OFF, ALLOW_ROW_LOCKS = ON, ALLOW_PAGE_LOCKS = ON) ON [PRIMARY] ) ON [PRIMARY] TEXTIMAGE_ON [PRIMARY] -END -GO"; +END;"; return batchSql; } } From 9acccdaefbfc9d93fd26edd3e1c75c8140f9d3da Mon Sep 17 00:00:00 2001 From: yangxiaodong Date: Mon, 17 Jul 2017 13:29:46 +0800 Subject: [PATCH 32/68] resolve database connectionstring into SqlServerOptions. --- .../CAP.SqlServerCapOptionsExtension.cs | 17 +++++++++++++++-- 1 file changed, 15 insertions(+), 2 deletions(-) diff --git a/src/DotNetCore.CAP.EntityFrameworkCore/CAP.SqlServerCapOptionsExtension.cs b/src/DotNetCore.CAP.EntityFrameworkCore/CAP.SqlServerCapOptionsExtension.cs index 204cc49..fe3d97b 100644 --- a/src/DotNetCore.CAP.EntityFrameworkCore/CAP.SqlServerCapOptionsExtension.cs +++ b/src/DotNetCore.CAP.EntityFrameworkCore/CAP.SqlServerCapOptionsExtension.cs @@ -1,6 +1,7 @@ using System; using DotNetCore.CAP.EntityFrameworkCore; using DotNetCore.CAP.Processor; +using Microsoft.EntityFrameworkCore; using Microsoft.Extensions.DependencyInjection; // ReSharper disable once CheckNamespace @@ -22,11 +23,23 @@ namespace DotNetCore.CAP services.AddScoped(); services.AddTransient(); - services.Configure(_configure); - var sqlServerOptions = new SqlServerOptions(); _configure(sqlServerOptions); + + var provider = TempBuildService(services); + var dbContextObj = provider.GetService(sqlServerOptions.DbContextType); + if (dbContextObj != null) + { + var dbContext = (DbContext)dbContextObj; + sqlServerOptions.ConnectionString = dbContext.Database.GetDbConnection().ConnectionString; + } + services.Configure(_configure); services.AddSingleton(sqlServerOptions); } + + private IServiceProvider TempBuildService(IServiceCollection services) + { + return services.BuildServiceProvider(); + } } } \ No newline at end of file From 5583f6af7db9b44f222a3fad1c305a964a47dd33 Mon Sep 17 00:00:00 2001 From: yangxiaodong Date: Mon, 17 Jul 2017 13:30:41 +0800 Subject: [PATCH 33/68] update options configuration. --- .../CAP.EFOptions.cs | 14 ++------------ .../CAP.Options.Extensions.cs | 1 + .../SqlServerStorageConnection.cs | 5 ++--- .../RabbitMQConsumerClient.cs | 2 +- 4 files changed, 6 insertions(+), 16 deletions(-) diff --git a/src/DotNetCore.CAP.EntityFrameworkCore/CAP.EFOptions.cs b/src/DotNetCore.CAP.EntityFrameworkCore/CAP.EFOptions.cs index 68aa524..6d162c5 100644 --- a/src/DotNetCore.CAP.EntityFrameworkCore/CAP.EFOptions.cs +++ b/src/DotNetCore.CAP.EntityFrameworkCore/CAP.EFOptions.cs @@ -5,8 +5,7 @@ namespace DotNetCore.CAP { public class EFOptions { - public const string DefaultSchema = "cap"; - public const string DefaultMigrationsHistoryTableName = "__EFMigrationsHistory"; + public const string DefaultSchema = "Cap"; /// /// Gets or sets the schema to use when creating database objects. @@ -15,17 +14,8 @@ namespace DotNetCore.CAP public string Schema { get; set; } = DefaultSchema; /// - /// Gets or sets the migrations history table's schema. - /// If this is null, will be used. + /// EF dbcontext type. /// - public string MigrationsHistoryTableSchema { get; set; } - - /// - /// Gets or sets the migrations history table's name. - /// Default is . - /// - public string MigrationsHistoryTableName { get; set; } = DefaultMigrationsHistoryTableName; - public Type DbContextType { get; internal set; } } } \ No newline at end of file diff --git a/src/DotNetCore.CAP.EntityFrameworkCore/CAP.Options.Extensions.cs b/src/DotNetCore.CAP.EntityFrameworkCore/CAP.Options.Extensions.cs index 0c1b6f8..d87e260 100644 --- a/src/DotNetCore.CAP.EntityFrameworkCore/CAP.Options.Extensions.cs +++ b/src/DotNetCore.CAP.EntityFrameworkCore/CAP.Options.Extensions.cs @@ -40,6 +40,7 @@ namespace Microsoft.Extensions.DependencyInjection var efOptions = new EFOptions { DbContextType = typeof(TContext) }; configure(efOptions); + options.RegisterExtension(new SqlServerCapOptionsExtension(configure)); return options; diff --git a/src/DotNetCore.CAP.EntityFrameworkCore/SqlServerStorageConnection.cs b/src/DotNetCore.CAP.EntityFrameworkCore/SqlServerStorageConnection.cs index eee5ac7..6dd326a 100644 --- a/src/DotNetCore.CAP.EntityFrameworkCore/SqlServerStorageConnection.cs +++ b/src/DotNetCore.CAP.EntityFrameworkCore/SqlServerStorageConnection.cs @@ -6,7 +6,6 @@ using Dapper; using DotNetCore.CAP.Infrastructure; using DotNetCore.CAP.Models; using Microsoft.EntityFrameworkCore; -using Microsoft.Extensions.Options; namespace DotNetCore.CAP.EntityFrameworkCore { @@ -14,9 +13,9 @@ namespace DotNetCore.CAP.EntityFrameworkCore { private readonly SqlServerOptions _options; - public SqlServerStorageConnection(IOptions options) + public SqlServerStorageConnection(SqlServerOptions options) { - _options = options.Value; + _options = options; } public SqlServerOptions Options => _options; diff --git a/src/DotNetCore.CAP.RabbitMQ/RabbitMQConsumerClient.cs b/src/DotNetCore.CAP.RabbitMQ/RabbitMQConsumerClient.cs index 7e19de1..26b0bf6 100644 --- a/src/DotNetCore.CAP.RabbitMQ/RabbitMQConsumerClient.cs +++ b/src/DotNetCore.CAP.RabbitMQ/RabbitMQConsumerClient.cs @@ -46,7 +46,7 @@ namespace DotNetCore.CAP.RabbitMQ _connection = _connectionFactory.CreateConnection(); _channel = _connection.CreateModel(); - _channel.ExchangeDeclare(exchange: _exchageName, type: _rabbitMQOptions.ExchangeType); + _channel.ExchangeDeclare(exchange: _exchageName, type: RabbitMQOptions.ExchangeType); _channel.QueueDeclare(_queueName, exclusive: false); } From 9de285b5dd32affc36fde6040ce18b0b8e60c1d9 Mon Sep 17 00:00:00 2001 From: yangxiaodong Date: Mon, 17 Jul 2017 13:31:39 +0800 Subject: [PATCH 34/68] modify CapOptions Extension to support multiple extensions. --- src/DotNetCore.CAP/CAP.Options.cs | 9 +++++++-- src/DotNetCore.CAP/CAP.ServiceCollectionExtensions.cs | 7 +++++-- 2 files changed, 12 insertions(+), 4 deletions(-) diff --git a/src/DotNetCore.CAP/CAP.Options.cs b/src/DotNetCore.CAP/CAP.Options.cs index de6d1ae..1e8253c 100644 --- a/src/DotNetCore.CAP/CAP.Options.cs +++ b/src/DotNetCore.CAP/CAP.Options.cs @@ -1,4 +1,5 @@ using System; +using System.Collections.Generic; namespace DotNetCore.CAP { @@ -7,7 +8,7 @@ namespace DotNetCore.CAP /// public class CapOptions { - internal ICapOptionsExtension Extension { get; private set; } + internal IList Extensions { get; private set; } /// /// Default value for polling delay timeout, in seconds. @@ -23,6 +24,7 @@ namespace DotNetCore.CAP { CronExp = DefaultCronExp; PollingDelay = DefaultPollingDelay; + Extensions = new List(); } /// @@ -41,7 +43,10 @@ namespace DotNetCore.CAP /// public void RegisterExtension(ICapOptionsExtension extension) { - Extension = extension ?? throw new ArgumentNullException(nameof(extension)); + if (extension == null) + throw new ArgumentNullException(nameof(extension)); + + Extensions.Add(extension); } } } \ No newline at end of file diff --git a/src/DotNetCore.CAP/CAP.ServiceCollectionExtensions.cs b/src/DotNetCore.CAP/CAP.ServiceCollectionExtensions.cs index 2ba0faa..e025ea6 100644 --- a/src/DotNetCore.CAP/CAP.ServiceCollectionExtensions.cs +++ b/src/DotNetCore.CAP/CAP.ServiceCollectionExtensions.cs @@ -53,10 +53,13 @@ namespace Microsoft.Extensions.DependencyInjection services.AddSingleton(); services.AddSingleton(); - //Options + //Options and extension service var options = new CapOptions(); setupAction(options); - options.Extension?.AddServices(services); + foreach (var serviceExtension in options.Extensions) + { + serviceExtension.AddServices(services); + } services.AddSingleton(options); return new CapBuilder(services); From f78a3a239022009fa9184fc0e561eb285fb33d26 Mon Sep 17 00:00:00 2001 From: yangxiaodong Date: Mon, 17 Jul 2017 13:55:36 +0800 Subject: [PATCH 35/68] remove ncoretab dependency. --- src/DotNetCore.CAP/CAP.Options.cs | 11 ----------- src/DotNetCore.CAP/DotNetCore.CAP.csproj | 1 - 2 files changed, 12 deletions(-) diff --git a/src/DotNetCore.CAP/CAP.Options.cs b/src/DotNetCore.CAP/CAP.Options.cs index 1e8253c..850d6dd 100644 --- a/src/DotNetCore.CAP/CAP.Options.cs +++ b/src/DotNetCore.CAP/CAP.Options.cs @@ -15,23 +15,12 @@ namespace DotNetCore.CAP /// public const int DefaultPollingDelay = 8; - /// - /// Default value for CAP job. - /// - public const string DefaultCronExp = "* * * * *"; - public CapOptions() { - CronExp = DefaultCronExp; PollingDelay = DefaultPollingDelay; Extensions = new List(); } - /// - /// Corn expression for configuring retry cron job. Default is 1 min. - /// - public string CronExp { get; set; } - /// /// Productor job polling delay time. Default is 8 sec. /// diff --git a/src/DotNetCore.CAP/DotNetCore.CAP.csproj b/src/DotNetCore.CAP/DotNetCore.CAP.csproj index bc8227c..2bf7ab4 100644 --- a/src/DotNetCore.CAP/DotNetCore.CAP.csproj +++ b/src/DotNetCore.CAP/DotNetCore.CAP.csproj @@ -20,7 +20,6 @@ - From 878b401854499a80a3dd22210a22c6b7ebcc8c56 Mon Sep 17 00:00:00 2001 From: yangxiaodong Date: Mon, 17 Jul 2017 14:10:07 +0800 Subject: [PATCH 36/68] rename project namespace. --- .../CAP.SqlServerCapOptionsExtension.cs | 2 +- .../CapPublisher.cs | 2 +- ...orkCore.csproj => DotNetCore.CAP.SqlServer.csproj} | 11 +++-------- .../FetchedMessage.cs | 2 +- .../IAdditionalProcessor.Default.cs | 2 +- .../SqlServerFetchedMessage.cs | 2 +- .../SqlServerStorage.cs | 3 +-- .../SqlServerStorageConnection.cs | 4 ++-- .../SqlServerStorageTransaction.cs | 2 +- .../DotNetCore.CAP.EntityFrameworkCore.Test.csproj | 2 +- 10 files changed, 13 insertions(+), 19 deletions(-) rename src/DotNetCore.CAP.EntityFrameworkCore/{DotNetCore.CAP.EntityFrameworkCore.csproj => DotNetCore.CAP.SqlServer.csproj} (64%) diff --git a/src/DotNetCore.CAP.EntityFrameworkCore/CAP.SqlServerCapOptionsExtension.cs b/src/DotNetCore.CAP.EntityFrameworkCore/CAP.SqlServerCapOptionsExtension.cs index fe3d97b..0425b8f 100644 --- a/src/DotNetCore.CAP.EntityFrameworkCore/CAP.SqlServerCapOptionsExtension.cs +++ b/src/DotNetCore.CAP.EntityFrameworkCore/CAP.SqlServerCapOptionsExtension.cs @@ -1,6 +1,6 @@ using System; -using DotNetCore.CAP.EntityFrameworkCore; using DotNetCore.CAP.Processor; +using DotNetCore.CAP.SqlServer; using Microsoft.EntityFrameworkCore; using Microsoft.Extensions.DependencyInjection; diff --git a/src/DotNetCore.CAP.EntityFrameworkCore/CapPublisher.cs b/src/DotNetCore.CAP.EntityFrameworkCore/CapPublisher.cs index e90bdad..3cba0a0 100644 --- a/src/DotNetCore.CAP.EntityFrameworkCore/CapPublisher.cs +++ b/src/DotNetCore.CAP.EntityFrameworkCore/CapPublisher.cs @@ -8,7 +8,7 @@ using DotNetCore.CAP.Processor; using Microsoft.EntityFrameworkCore; using Microsoft.EntityFrameworkCore.Storage; -namespace DotNetCore.CAP.EntityFrameworkCore +namespace DotNetCore.CAP.SqlServer { public class CapPublisher : ICapPublisher { diff --git a/src/DotNetCore.CAP.EntityFrameworkCore/DotNetCore.CAP.EntityFrameworkCore.csproj b/src/DotNetCore.CAP.EntityFrameworkCore/DotNetCore.CAP.SqlServer.csproj similarity index 64% rename from src/DotNetCore.CAP.EntityFrameworkCore/DotNetCore.CAP.EntityFrameworkCore.csproj rename to src/DotNetCore.CAP.EntityFrameworkCore/DotNetCore.CAP.SqlServer.csproj index d532199..c2b12cb 100644 --- a/src/DotNetCore.CAP.EntityFrameworkCore/DotNetCore.CAP.EntityFrameworkCore.csproj +++ b/src/DotNetCore.CAP.EntityFrameworkCore/DotNetCore.CAP.SqlServer.csproj @@ -4,8 +4,8 @@ netstandard1.6 - DotNetCore.CAP.EntityFrameworkCore - DotNetCore.CAP.EntityFrameworkCore + DotNetCore.CAP.SqlServer + DotNetCore.CAP.SqlServer 1.6.1 $(PackageTargetFallback);dnxcore50 false @@ -16,12 +16,7 @@ - - - - - - + diff --git a/src/DotNetCore.CAP.EntityFrameworkCore/FetchedMessage.cs b/src/DotNetCore.CAP.EntityFrameworkCore/FetchedMessage.cs index 13dbc0f..521fdeb 100644 --- a/src/DotNetCore.CAP.EntityFrameworkCore/FetchedMessage.cs +++ b/src/DotNetCore.CAP.EntityFrameworkCore/FetchedMessage.cs @@ -1,6 +1,6 @@ using DotNetCore.CAP.Models; -namespace DotNetCore.CAP.EntityFrameworkCore +namespace DotNetCore.CAP.SqlServer { public class FetchedMessage { diff --git a/src/DotNetCore.CAP.EntityFrameworkCore/IAdditionalProcessor.Default.cs b/src/DotNetCore.CAP.EntityFrameworkCore/IAdditionalProcessor.Default.cs index 89126ac..65490ab 100644 --- a/src/DotNetCore.CAP.EntityFrameworkCore/IAdditionalProcessor.Default.cs +++ b/src/DotNetCore.CAP.EntityFrameworkCore/IAdditionalProcessor.Default.cs @@ -5,7 +5,7 @@ using Dapper; using DotNetCore.CAP.Processor; using Microsoft.Extensions.Logging; -namespace DotNetCore.CAP.EntityFrameworkCore +namespace DotNetCore.CAP.SqlServer { public class DefaultAdditionalProcessor : IAdditionalProcessor { diff --git a/src/DotNetCore.CAP.EntityFrameworkCore/SqlServerFetchedMessage.cs b/src/DotNetCore.CAP.EntityFrameworkCore/SqlServerFetchedMessage.cs index 6e9d8e2..06bc461 100644 --- a/src/DotNetCore.CAP.EntityFrameworkCore/SqlServerFetchedMessage.cs +++ b/src/DotNetCore.CAP.EntityFrameworkCore/SqlServerFetchedMessage.cs @@ -4,7 +4,7 @@ using System.Threading; using Dapper; using DotNetCore.CAP.Models; -namespace DotNetCore.CAP.EntityFrameworkCore +namespace DotNetCore.CAP.SqlServer { public class SqlServerFetchedMessage : IFetchedMessage { diff --git a/src/DotNetCore.CAP.EntityFrameworkCore/SqlServerStorage.cs b/src/DotNetCore.CAP.EntityFrameworkCore/SqlServerStorage.cs index 765d88f..57d7e5d 100644 --- a/src/DotNetCore.CAP.EntityFrameworkCore/SqlServerStorage.cs +++ b/src/DotNetCore.CAP.EntityFrameworkCore/SqlServerStorage.cs @@ -1,4 +1,3 @@ -using System; using System.Data.SqlClient; using System.Threading; using System.Threading.Tasks; @@ -6,7 +5,7 @@ using Dapper; using Microsoft.EntityFrameworkCore; using Microsoft.Extensions.Logging; -namespace DotNetCore.CAP.EntityFrameworkCore +namespace DotNetCore.CAP.SqlServer { public class SqlServerStorage : IStorage { diff --git a/src/DotNetCore.CAP.EntityFrameworkCore/SqlServerStorageConnection.cs b/src/DotNetCore.CAP.EntityFrameworkCore/SqlServerStorageConnection.cs index 6dd326a..78c2a2e 100644 --- a/src/DotNetCore.CAP.EntityFrameworkCore/SqlServerStorageConnection.cs +++ b/src/DotNetCore.CAP.EntityFrameworkCore/SqlServerStorageConnection.cs @@ -7,7 +7,7 @@ using DotNetCore.CAP.Infrastructure; using DotNetCore.CAP.Models; using Microsoft.EntityFrameworkCore; -namespace DotNetCore.CAP.EntityFrameworkCore +namespace DotNetCore.CAP.SqlServer { public class SqlServerStorageConnection : IStorageConnection { @@ -15,7 +15,7 @@ namespace DotNetCore.CAP.EntityFrameworkCore public SqlServerStorageConnection(SqlServerOptions options) { - _options = options; + _options = options; } public SqlServerOptions Options => _options; diff --git a/src/DotNetCore.CAP.EntityFrameworkCore/SqlServerStorageTransaction.cs b/src/DotNetCore.CAP.EntityFrameworkCore/SqlServerStorageTransaction.cs index 81dd805..f1421b1 100644 --- a/src/DotNetCore.CAP.EntityFrameworkCore/SqlServerStorageTransaction.cs +++ b/src/DotNetCore.CAP.EntityFrameworkCore/SqlServerStorageTransaction.cs @@ -5,7 +5,7 @@ using System.Threading.Tasks; using Dapper; using DotNetCore.CAP.Models; -namespace DotNetCore.CAP.EntityFrameworkCore +namespace DotNetCore.CAP.SqlServer { public class SqlServerStorageTransaction : IStorageTransaction, IDisposable { diff --git a/test/DotNetCore.CAP.EntityFrameworkCore.Test/DotNetCore.CAP.EntityFrameworkCore.Test.csproj b/test/DotNetCore.CAP.EntityFrameworkCore.Test/DotNetCore.CAP.EntityFrameworkCore.Test.csproj index 8a35540..53b28ec 100644 --- a/test/DotNetCore.CAP.EntityFrameworkCore.Test/DotNetCore.CAP.EntityFrameworkCore.Test.csproj +++ b/test/DotNetCore.CAP.EntityFrameworkCore.Test/DotNetCore.CAP.EntityFrameworkCore.Test.csproj @@ -18,8 +18,8 @@ + - From 95b2cdff0f96060c9167b39f30857c15d85514f2 Mon Sep 17 00:00:00 2001 From: yangxiaodong Date: Mon, 17 Jul 2017 14:27:07 +0800 Subject: [PATCH 37/68] modify project physical path. --- .../CAP.EFOptions.cs | 0 .../CAP.Options.Extensions.cs | 0 .../CAP.SqlServerCapOptionsExtension.cs | 0 .../CAP.SqlServerOptions.cs | 0 .../CapPublisher.cs | 0 .../DotNetCore.CAP.SqlServer.csproj | 0 .../FetchedMessage.cs | 0 .../IAdditionalProcessor.Default.cs | 0 .../SqlServerFetchedMessage.cs | 0 .../SqlServerStorage.cs | 0 .../SqlServerStorageConnection.cs | 0 .../SqlServerStorageTransaction.cs | 0 12 files changed, 0 insertions(+), 0 deletions(-) rename src/{DotNetCore.CAP.EntityFrameworkCore => DotNetCore.CAP.SqlServer}/CAP.EFOptions.cs (100%) rename src/{DotNetCore.CAP.EntityFrameworkCore => DotNetCore.CAP.SqlServer}/CAP.Options.Extensions.cs (100%) rename src/{DotNetCore.CAP.EntityFrameworkCore => DotNetCore.CAP.SqlServer}/CAP.SqlServerCapOptionsExtension.cs (100%) rename src/{DotNetCore.CAP.EntityFrameworkCore => DotNetCore.CAP.SqlServer}/CAP.SqlServerOptions.cs (100%) rename src/{DotNetCore.CAP.EntityFrameworkCore => DotNetCore.CAP.SqlServer}/CapPublisher.cs (100%) rename src/{DotNetCore.CAP.EntityFrameworkCore => DotNetCore.CAP.SqlServer}/DotNetCore.CAP.SqlServer.csproj (100%) rename src/{DotNetCore.CAP.EntityFrameworkCore => DotNetCore.CAP.SqlServer}/FetchedMessage.cs (100%) rename src/{DotNetCore.CAP.EntityFrameworkCore => DotNetCore.CAP.SqlServer}/IAdditionalProcessor.Default.cs (100%) rename src/{DotNetCore.CAP.EntityFrameworkCore => DotNetCore.CAP.SqlServer}/SqlServerFetchedMessage.cs (100%) rename src/{DotNetCore.CAP.EntityFrameworkCore => DotNetCore.CAP.SqlServer}/SqlServerStorage.cs (100%) rename src/{DotNetCore.CAP.EntityFrameworkCore => DotNetCore.CAP.SqlServer}/SqlServerStorageConnection.cs (100%) rename src/{DotNetCore.CAP.EntityFrameworkCore => DotNetCore.CAP.SqlServer}/SqlServerStorageTransaction.cs (100%) diff --git a/src/DotNetCore.CAP.EntityFrameworkCore/CAP.EFOptions.cs b/src/DotNetCore.CAP.SqlServer/CAP.EFOptions.cs similarity index 100% rename from src/DotNetCore.CAP.EntityFrameworkCore/CAP.EFOptions.cs rename to src/DotNetCore.CAP.SqlServer/CAP.EFOptions.cs diff --git a/src/DotNetCore.CAP.EntityFrameworkCore/CAP.Options.Extensions.cs b/src/DotNetCore.CAP.SqlServer/CAP.Options.Extensions.cs similarity index 100% rename from src/DotNetCore.CAP.EntityFrameworkCore/CAP.Options.Extensions.cs rename to src/DotNetCore.CAP.SqlServer/CAP.Options.Extensions.cs diff --git a/src/DotNetCore.CAP.EntityFrameworkCore/CAP.SqlServerCapOptionsExtension.cs b/src/DotNetCore.CAP.SqlServer/CAP.SqlServerCapOptionsExtension.cs similarity index 100% rename from src/DotNetCore.CAP.EntityFrameworkCore/CAP.SqlServerCapOptionsExtension.cs rename to src/DotNetCore.CAP.SqlServer/CAP.SqlServerCapOptionsExtension.cs diff --git a/src/DotNetCore.CAP.EntityFrameworkCore/CAP.SqlServerOptions.cs b/src/DotNetCore.CAP.SqlServer/CAP.SqlServerOptions.cs similarity index 100% rename from src/DotNetCore.CAP.EntityFrameworkCore/CAP.SqlServerOptions.cs rename to src/DotNetCore.CAP.SqlServer/CAP.SqlServerOptions.cs diff --git a/src/DotNetCore.CAP.EntityFrameworkCore/CapPublisher.cs b/src/DotNetCore.CAP.SqlServer/CapPublisher.cs similarity index 100% rename from src/DotNetCore.CAP.EntityFrameworkCore/CapPublisher.cs rename to src/DotNetCore.CAP.SqlServer/CapPublisher.cs diff --git a/src/DotNetCore.CAP.EntityFrameworkCore/DotNetCore.CAP.SqlServer.csproj b/src/DotNetCore.CAP.SqlServer/DotNetCore.CAP.SqlServer.csproj similarity index 100% rename from src/DotNetCore.CAP.EntityFrameworkCore/DotNetCore.CAP.SqlServer.csproj rename to src/DotNetCore.CAP.SqlServer/DotNetCore.CAP.SqlServer.csproj diff --git a/src/DotNetCore.CAP.EntityFrameworkCore/FetchedMessage.cs b/src/DotNetCore.CAP.SqlServer/FetchedMessage.cs similarity index 100% rename from src/DotNetCore.CAP.EntityFrameworkCore/FetchedMessage.cs rename to src/DotNetCore.CAP.SqlServer/FetchedMessage.cs diff --git a/src/DotNetCore.CAP.EntityFrameworkCore/IAdditionalProcessor.Default.cs b/src/DotNetCore.CAP.SqlServer/IAdditionalProcessor.Default.cs similarity index 100% rename from src/DotNetCore.CAP.EntityFrameworkCore/IAdditionalProcessor.Default.cs rename to src/DotNetCore.CAP.SqlServer/IAdditionalProcessor.Default.cs diff --git a/src/DotNetCore.CAP.EntityFrameworkCore/SqlServerFetchedMessage.cs b/src/DotNetCore.CAP.SqlServer/SqlServerFetchedMessage.cs similarity index 100% rename from src/DotNetCore.CAP.EntityFrameworkCore/SqlServerFetchedMessage.cs rename to src/DotNetCore.CAP.SqlServer/SqlServerFetchedMessage.cs diff --git a/src/DotNetCore.CAP.EntityFrameworkCore/SqlServerStorage.cs b/src/DotNetCore.CAP.SqlServer/SqlServerStorage.cs similarity index 100% rename from src/DotNetCore.CAP.EntityFrameworkCore/SqlServerStorage.cs rename to src/DotNetCore.CAP.SqlServer/SqlServerStorage.cs diff --git a/src/DotNetCore.CAP.EntityFrameworkCore/SqlServerStorageConnection.cs b/src/DotNetCore.CAP.SqlServer/SqlServerStorageConnection.cs similarity index 100% rename from src/DotNetCore.CAP.EntityFrameworkCore/SqlServerStorageConnection.cs rename to src/DotNetCore.CAP.SqlServer/SqlServerStorageConnection.cs diff --git a/src/DotNetCore.CAP.EntityFrameworkCore/SqlServerStorageTransaction.cs b/src/DotNetCore.CAP.SqlServer/SqlServerStorageTransaction.cs similarity index 100% rename from src/DotNetCore.CAP.EntityFrameworkCore/SqlServerStorageTransaction.cs rename to src/DotNetCore.CAP.SqlServer/SqlServerStorageTransaction.cs From 0c9029404d768a05a412da85e167688f3513e94f Mon Sep 17 00:00:00 2001 From: yangxiaodong Date: Mon, 17 Jul 2017 16:10:42 +0800 Subject: [PATCH 38/68] add webhook support. --- src/DotNetCore.CAP/CAP.Options.cs | 12 ++++++++++++ src/DotNetCore.CAP/Infrastructure/WebHookProvider.cs | 10 ++++++++++ 2 files changed, 22 insertions(+) create mode 100644 src/DotNetCore.CAP/Infrastructure/WebHookProvider.cs diff --git a/src/DotNetCore.CAP/CAP.Options.cs b/src/DotNetCore.CAP/CAP.Options.cs index 850d6dd..334c709 100644 --- a/src/DotNetCore.CAP/CAP.Options.cs +++ b/src/DotNetCore.CAP/CAP.Options.cs @@ -26,6 +26,11 @@ namespace DotNetCore.CAP /// public int PollingDelay { get; set; } = 8; + /// + /// We’ll send a POST request to the URL below with details of any subscribed events. + /// + public WebHook WebHook { get; set; } + /// /// Registers an extension that will be executed when building services. /// @@ -38,4 +43,11 @@ namespace DotNetCore.CAP Extensions.Add(extension); } } + + public class WebHook + { + public string PayloadUrl { get; set; } + + public string Secret { get; set; } + } } \ No newline at end of file diff --git a/src/DotNetCore.CAP/Infrastructure/WebHookProvider.cs b/src/DotNetCore.CAP/Infrastructure/WebHookProvider.cs new file mode 100644 index 0000000..49039f6 --- /dev/null +++ b/src/DotNetCore.CAP/Infrastructure/WebHookProvider.cs @@ -0,0 +1,10 @@ +using System; +using System.Collections.Generic; +using System.Text; + +namespace DotNetCore.CAP.Infrastructure +{ + class WebHookProvider + { + } +} From 6cae200e4d42665d86734c61d712979a6719dc1f Mon Sep 17 00:00:00 2001 From: yangxiaodong Date: Mon, 17 Jul 2017 16:12:06 +0800 Subject: [PATCH 39/68] fix bug. --- .../SqlServerStorageConnection.cs | 53 ++++++------ .../SqlServerStorageTransaction.cs | 13 +-- .../IConsumerHandler.Default.cs | 2 +- .../IQueueExecutor.Publish.Base.cs | 75 +++++++++-------- src/DotNetCore.CAP/IQueueExecutor.Subscibe.cs | 81 +++++++++---------- ...etCore.CAP.EntityFrameworkCore.Test.csproj | 2 +- 6 files changed, 113 insertions(+), 113 deletions(-) diff --git a/src/DotNetCore.CAP.SqlServer/SqlServerStorageConnection.cs b/src/DotNetCore.CAP.SqlServer/SqlServerStorageConnection.cs index 78c2a2e..b5d56c3 100644 --- a/src/DotNetCore.CAP.SqlServer/SqlServerStorageConnection.cs +++ b/src/DotNetCore.CAP.SqlServer/SqlServerStorageConnection.cs @@ -25,12 +25,13 @@ namespace DotNetCore.CAP.SqlServer return new SqlServerStorageTransaction(this); } - public Task GetPublishedMessageAsync(int id) + public async Task GetPublishedMessageAsync(int id) { var sql = $@"SELECT * FROM [{_options.Schema}].[Published] WITH (readpast) WHERE Id={id}"; + using (var connection = new SqlConnection(_options.ConnectionString)) { - return connection.QueryFirstOrDefaultAsync(sql); + return await connection.QueryFirstOrDefaultAsync(sql); } } @@ -56,7 +57,7 @@ OUTPUT DELETED.MessageId,DELETED.[MessageType];"; // CapReceviedMessage - public Task StoreReceivedMessageAsync(CapReceivedMessage message) + public async Task StoreReceivedMessageAsync(CapReceivedMessage message) { if (message == null) throw new ArgumentNullException(nameof(message)); @@ -66,16 +67,16 @@ VALUES(@Name,@Group,@Content,@Retries,@Added,@ExpiresAt,@StatusName);"; using (var connection = new SqlConnection(_options.ConnectionString)) { - return connection.ExecuteAsync(sql, message); + await connection.ExecuteAsync(sql, message); } } - public Task GetReceivedMessageAsync(int id) + public async Task GetReceivedMessageAsync(int id) { var sql = $@"SELECT * FROM [{_options.Schema}].[Received] WITH (readpast) WHERE Id={id}"; using (var connection = new SqlConnection(_options.ConnectionString)) { - return connection.QueryFirstOrDefaultAsync(sql); + return await connection.QueryFirstOrDefaultAsync(sql); } } @@ -94,26 +95,30 @@ VALUES(@Name,@Group,@Content,@Retries,@Added,@ExpiresAt,@StatusName);"; private async Task FetchNextMessageCoreAsync(string sql, object args = null) { - using (var connection = new SqlConnection(_options.ConnectionString)) + //here don't use `using` to dispose + var connection = new SqlConnection(_options.ConnectionString); + await connection.OpenAsync(); + var transaction = connection.BeginTransaction(IsolationLevel.ReadCommitted); + FetchedMessage fetchedMessage = null; + try + { + fetchedMessage = await connection.QueryFirstOrDefaultAsync(sql, args, transaction); + } + catch (SqlException) { - using (var transaction = connection.BeginTransaction(IsolationLevel.ReadCommitted)) - { - try - { - var fetched = await connection.QueryFirstOrDefaultAsync(sql, args, transaction); - - if (fetched == null) - return null; - - return new SqlServerFetchedMessage(fetched.MessageId, fetched.MessageType, connection, transaction); - } - catch (Exception) - { - transaction.Rollback(); - return null; - } - } + transaction.Dispose(); + throw; } + + if (fetchedMessage == null) + { + transaction.Rollback(); + transaction.Dispose(); + connection.Dispose(); + return null; + } + + return new SqlServerFetchedMessage(fetchedMessage.MessageId, fetchedMessage.MessageType, connection, transaction); } } } \ No newline at end of file diff --git a/src/DotNetCore.CAP.SqlServer/SqlServerStorageTransaction.cs b/src/DotNetCore.CAP.SqlServer/SqlServerStorageTransaction.cs index f1421b1..b30c616 100644 --- a/src/DotNetCore.CAP.SqlServer/SqlServerStorageTransaction.cs +++ b/src/DotNetCore.CAP.SqlServer/SqlServerStorageTransaction.cs @@ -20,6 +20,7 @@ namespace DotNetCore.CAP.SqlServer _schema = options.Schema; _dbConnection = new SqlConnection(options.ConnectionString); + _dbConnection.Open(); _dbTransaction = _dbConnection.BeginTransaction(IsolationLevel.ReadCommitted); } @@ -27,16 +28,16 @@ namespace DotNetCore.CAP.SqlServer { if (message == null) throw new ArgumentNullException(nameof(message)); - var sql = $"UPDATE [{_schema}].[Published] SET [ExpiresAt] = @ExpiresAt,[StatusName]=@StatusName WHERE Id=@Id;"; - _dbConnection.Execute(sql, message); + var sql = $"UPDATE [{_schema}].[Published] SET [Retries] = @Retries,[ExpiresAt] = @ExpiresAt,[StatusName]=@StatusName WHERE Id=@Id;"; + _dbConnection.Execute(sql, message, _dbTransaction); } public void UpdateMessage(CapReceivedMessage message) { if (message == null) throw new ArgumentNullException(nameof(message)); - var sql = $"UPDATE [{_schema}].[Received] SET [ExpiresAt] = @ExpiresAt,[StatusName]=@StatusName WHERE Id=@Id;"; - _dbConnection.Execute(sql, message); + var sql = $"UPDATE [{_schema}].[Received] SET [Retries] = @Retries,[ExpiresAt] = @ExpiresAt,[StatusName]=@StatusName WHERE Id=@Id;"; + _dbConnection.Execute(sql, message, _dbTransaction); } public void EnqueueMessage(CapPublishedMessage message) @@ -44,7 +45,7 @@ namespace DotNetCore.CAP.SqlServer if (message == null) throw new ArgumentNullException(nameof(message)); var sql = $"INSERT INTO [{_schema}].[Queue] values(@MessageId,@MessageType);"; - _dbConnection.Execute(sql, new CapQueue { MessageId = message.Id, MessageType = MessageType.Publish }); + _dbConnection.Execute(sql, new CapQueue { MessageId = message.Id, MessageType = MessageType.Publish }, _dbTransaction); } public void EnqueueMessage(CapReceivedMessage message) @@ -52,7 +53,7 @@ namespace DotNetCore.CAP.SqlServer if (message == null) throw new ArgumentNullException(nameof(message)); var sql = $"INSERT INTO [{_schema}].[Queue] values(@MessageId,@MessageType);"; - _dbConnection.Execute(sql, new CapQueue { MessageId = message.Id, MessageType = MessageType.Subscribe }); + _dbConnection.Execute(sql, new CapQueue { MessageId = message.Id, MessageType = MessageType.Subscribe }, _dbTransaction); } public Task CommitAsync() diff --git a/src/DotNetCore.CAP/IConsumerHandler.Default.cs b/src/DotNetCore.CAP/IConsumerHandler.Default.cs index 0ca1949..f317b85 100644 --- a/src/DotNetCore.CAP/IConsumerHandler.Default.cs +++ b/src/DotNetCore.CAP/IConsumerHandler.Default.cs @@ -113,7 +113,7 @@ namespace DotNetCore.CAP var messageStore = provider.GetRequiredService(); var receivedMessage = new CapReceivedMessage(messageContext) { - StatusName = StatusName.Enqueued, + StatusName = StatusName.Scheduled, }; messageStore.StoreReceivedMessageAsync(receivedMessage).Wait(); return receivedMessage; diff --git a/src/DotNetCore.CAP/IQueueExecutor.Publish.Base.cs b/src/DotNetCore.CAP/IQueueExecutor.Publish.Base.cs index 10fd2eb..27742ab 100644 --- a/src/DotNetCore.CAP/IQueueExecutor.Publish.Base.cs +++ b/src/DotNetCore.CAP/IQueueExecutor.Publish.Base.cs @@ -24,56 +24,53 @@ namespace DotNetCore.CAP public async Task ExecuteAsync(IStorageConnection connection, IFetchedMessage fetched) { - using (fetched) + var message = await connection.GetPublishedMessageAsync(fetched.MessageId); + try { - var message = await connection.GetPublishedMessageAsync(fetched.MessageId); - try - { - var sp = Stopwatch.StartNew(); - await _stateChanger.ChangeStateAsync(message, new ProcessingState(), connection); + var sp = Stopwatch.StartNew(); + await _stateChanger.ChangeStateAsync(message, new ProcessingState(), connection); - if (message.Retries > 0) - { - _logger.JobRetrying(message.Retries); - } - var result = await PublishAsync(message.Name, message.Content); - sp.Stop(); + if (message.Retries > 0) + { + _logger.JobRetrying(message.Retries); + } + var result = await PublishAsync(message.Name, message.Content); + sp.Stop(); - var newState = default(IState); - if (!result.Succeeded) + var newState = default(IState); + if (!result.Succeeded) + { + var shouldRetry = await UpdateJobForRetryAsync(message, connection); + if (shouldRetry) { - var shouldRetry = await UpdateJobForRetryAsync(message, connection); - if (shouldRetry) - { - newState = new ScheduledState(); - _logger.JobFailedWillRetry(result.Exception); - } - else - { - newState = new FailedState(); - _logger.JobFailed(result.Exception); - } + newState = new ScheduledState(); + _logger.JobFailedWillRetry(result.Exception); } else { - newState = new SucceededState(); + newState = new FailedState(); + _logger.JobFailed(result.Exception); } - await _stateChanger.ChangeStateAsync(message, newState, connection); - - fetched.RemoveFromQueue(); + } + else + { + newState = new SucceededState(); + } + await _stateChanger.ChangeStateAsync(message, newState, connection); - if (result.Succeeded) - { - _logger.JobExecuted(sp.Elapsed.TotalSeconds); - } + fetched.RemoveFromQueue(); - return OperateResult.Success; - } - catch (Exception ex) + if (result.Succeeded) { - _logger.ExceptionOccuredWhileExecutingJob(message?.Name, ex); - return OperateResult.Failed(ex); + _logger.JobExecuted(sp.Elapsed.TotalSeconds); } + + return OperateResult.Success; + } + catch (Exception ex) + { + _logger.ExceptionOccuredWhileExecutingJob(message?.Name, ex); + return OperateResult.Failed(ex); } } @@ -81,7 +78,7 @@ namespace DotNetCore.CAP { var retryBehavior = RetryBehavior.DefaultRetry; - var now = DateTime.UtcNow; + var now = DateTime.Now; var retries = ++message.Retries; if (retries >= retryBehavior.RetryCount) { diff --git a/src/DotNetCore.CAP/IQueueExecutor.Subscibe.cs b/src/DotNetCore.CAP/IQueueExecutor.Subscibe.cs index 503f2f3..6ea5095 100644 --- a/src/DotNetCore.CAP/IQueueExecutor.Subscibe.cs +++ b/src/DotNetCore.CAP/IQueueExecutor.Subscibe.cs @@ -37,61 +37,58 @@ namespace DotNetCore.CAP public async Task ExecuteAsync(IStorageConnection connection, IFetchedMessage fetched) { - using (fetched) + var message = await connection.GetReceivedMessageAsync(fetched.MessageId); + try { - var message = await connection.GetReceivedMessageAsync(fetched.MessageId); - try - { - var sp = Stopwatch.StartNew(); - await _stateChanger.ChangeStateAsync(message, new ProcessingState(), connection); + var sp = Stopwatch.StartNew(); + await _stateChanger.ChangeStateAsync(message, new ProcessingState(), connection); - if (message.Retries > 0) - { - _logger.JobRetrying(message.Retries); - } - var result = await ExecuteSubscribeAsync(message); - sp.Stop(); + if (message.Retries > 0) + { + _logger.JobRetrying(message.Retries); + } + var result = await ExecuteSubscribeAsync(message); + sp.Stop(); - var newState = default(IState); - if (!result.Succeeded) + var newState = default(IState); + if (!result.Succeeded) + { + var shouldRetry = await UpdateJobForRetryAsync(message, connection); + if (shouldRetry) { - var shouldRetry = await UpdateJobForRetryAsync(message, connection); - if (shouldRetry) - { - newState = new ScheduledState(); - _logger.JobFailedWillRetry(result.Exception); - } - else - { - newState = new FailedState(); - _logger.JobFailed(result.Exception); - } + newState = new ScheduledState(); + _logger.JobFailedWillRetry(result.Exception); } else { - newState = new SucceededState(); - } - await _stateChanger.ChangeStateAsync(message, newState, connection); - - fetched.RemoveFromQueue(); - - if (result.Succeeded) - { - _logger.JobExecuted(sp.Elapsed.TotalSeconds); + newState = new FailedState(); + _logger.JobFailed(result.Exception); } - - return OperateResult.Success; } - catch (SubscriberNotFoundException ex) + else { - _logger.LogError(ex.Message); - return OperateResult.Failed(ex); + newState = new SucceededState(); } - catch (Exception ex) + await _stateChanger.ChangeStateAsync(message, newState, connection); + + fetched.RemoveFromQueue(); + + if (result.Succeeded) { - _logger.ExceptionOccuredWhileExecutingJob(message?.Name, ex); - return OperateResult.Failed(ex); + _logger.JobExecuted(sp.Elapsed.TotalSeconds); } + + return OperateResult.Success; + } + catch (SubscriberNotFoundException ex) + { + _logger.LogError(ex.Message); + return OperateResult.Failed(ex); + } + catch (Exception ex) + { + _logger.ExceptionOccuredWhileExecutingJob(message?.Name, ex); + return OperateResult.Failed(ex); } } diff --git a/test/DotNetCore.CAP.EntityFrameworkCore.Test/DotNetCore.CAP.EntityFrameworkCore.Test.csproj b/test/DotNetCore.CAP.EntityFrameworkCore.Test/DotNetCore.CAP.EntityFrameworkCore.Test.csproj index 53b28ec..17da1b0 100644 --- a/test/DotNetCore.CAP.EntityFrameworkCore.Test/DotNetCore.CAP.EntityFrameworkCore.Test.csproj +++ b/test/DotNetCore.CAP.EntityFrameworkCore.Test/DotNetCore.CAP.EntityFrameworkCore.Test.csproj @@ -18,7 +18,7 @@ - + From fe777ded3800a4db398a6b61c76617f69849b7c9 Mon Sep 17 00:00:00 2001 From: yangxiaodong Date: Mon, 17 Jul 2017 16:12:14 +0800 Subject: [PATCH 40/68] update samples. --- CAP.sln | 16 ++++++++-------- samples/Sample.Kafka/AppDbContext.cs | 15 ++++----------- .../Sample.Kafka/Controllers/ValuesController.cs | 1 - samples/Sample.Kafka/Sample.Kafka.csproj | 2 +- samples/Sample.Kafka/Startup.cs | 4 ++-- 5 files changed, 15 insertions(+), 23 deletions(-) diff --git a/CAP.sln b/CAP.sln index fe54719..5a08718 100644 --- a/CAP.sln +++ b/CAP.sln @@ -1,7 +1,7 @@  Microsoft Visual Studio Solution File, Format Version 12.00 # Visual Studio 15 -VisualStudioVersion = 15.0.26430.14 +VisualStudioVersion = 15.0.26430.15 MinimumVisualStudioVersion = 10.0.40219.1 Project("{2150E333-8FDC-42A3-9474-1A3956D46DE8}") = "src", "src", "{9B2AE124-6636-4DE9-83A3-70360DABD0C4}" EndProject @@ -33,8 +33,6 @@ Project("{2150E333-8FDC-42A3-9474-1A3956D46DE8}") = "Shared", "Shared", "{9E5A7F EndProject Project("{9A19103F-16F7-4668-BE54-9A1E7A4F7556}") = "DotNetCore.CAP", "src\DotNetCore.CAP\DotNetCore.CAP.csproj", "{E8AF8611-0EA4-4B19-BC48-87C57A87DC66}" EndProject -Project("{9A19103F-16F7-4668-BE54-9A1E7A4F7556}") = "DotNetCore.CAP.EntityFrameworkCore", "src\DotNetCore.CAP.EntityFrameworkCore\DotNetCore.CAP.EntityFrameworkCore.csproj", "{96111249-C4C3-4DC9-A887-32D583723AB1}" -EndProject Project("{2150E333-8FDC-42A3-9474-1A3956D46DE8}") = "samples", "samples", "{3A6B6931-A123-477A-9469-8B468B5385AF}" EndProject Project("{9A19103F-16F7-4668-BE54-9A1E7A4F7556}") = "Sample.Kafka", "samples\Sample.Kafka\Sample.Kafka.csproj", "{2F095ED9-5BC9-4512-9013-A47685FB2508}" @@ -59,6 +57,8 @@ Project("{9A19103F-16F7-4668-BE54-9A1E7A4F7556}") = "DotNetCore.CAP.EntityFramew EndProject Project("{9A19103F-16F7-4668-BE54-9A1E7A4F7556}") = "DotNetCore.CAP.Test", "test\DotNetCore.CAP.Test\DotNetCore.CAP.Test.csproj", "{F608B509-A99B-4AC7-8227-42051DD4A578}" EndProject +Project("{9A19103F-16F7-4668-BE54-9A1E7A4F7556}") = "DotNetCore.CAP.SqlServer", "src\DotNetCore.CAP.SqlServer\DotNetCore.CAP.SqlServer.csproj", "{3B577468-6792-4EF1-9237-15180B176A24}" +EndProject Global GlobalSection(SolutionConfigurationPlatforms) = preSolution Debug|Any CPU = Debug|Any CPU @@ -69,10 +69,6 @@ Global {E8AF8611-0EA4-4B19-BC48-87C57A87DC66}.Debug|Any CPU.Build.0 = Debug|Any CPU {E8AF8611-0EA4-4B19-BC48-87C57A87DC66}.Release|Any CPU.ActiveCfg = Release|Any CPU {E8AF8611-0EA4-4B19-BC48-87C57A87DC66}.Release|Any CPU.Build.0 = Release|Any CPU - {96111249-C4C3-4DC9-A887-32D583723AB1}.Debug|Any CPU.ActiveCfg = Debug|Any CPU - {96111249-C4C3-4DC9-A887-32D583723AB1}.Debug|Any CPU.Build.0 = Debug|Any CPU - {96111249-C4C3-4DC9-A887-32D583723AB1}.Release|Any CPU.ActiveCfg = Release|Any CPU - {96111249-C4C3-4DC9-A887-32D583723AB1}.Release|Any CPU.Build.0 = Release|Any CPU {2F095ED9-5BC9-4512-9013-A47685FB2508}.Debug|Any CPU.ActiveCfg = Debug|Any CPU {2F095ED9-5BC9-4512-9013-A47685FB2508}.Debug|Any CPU.Build.0 = Debug|Any CPU {2F095ED9-5BC9-4512-9013-A47685FB2508}.Release|Any CPU.ActiveCfg = Release|Any CPU @@ -92,6 +88,10 @@ Global {F608B509-A99B-4AC7-8227-42051DD4A578}.Debug|Any CPU.ActiveCfg = Debug|Any CPU {F608B509-A99B-4AC7-8227-42051DD4A578}.Debug|Any CPU.Build.0 = Debug|Any CPU {F608B509-A99B-4AC7-8227-42051DD4A578}.Release|Any CPU.ActiveCfg = Release|Any CPU + {3B577468-6792-4EF1-9237-15180B176A24}.Debug|Any CPU.ActiveCfg = Debug|Any CPU + {3B577468-6792-4EF1-9237-15180B176A24}.Debug|Any CPU.Build.0 = Debug|Any CPU + {3B577468-6792-4EF1-9237-15180B176A24}.Release|Any CPU.ActiveCfg = Release|Any CPU + {3B577468-6792-4EF1-9237-15180B176A24}.Release|Any CPU.Build.0 = Release|Any CPU EndGlobalSection GlobalSection(SolutionProperties) = preSolution HideSolutionNode = FALSE @@ -99,11 +99,11 @@ Global GlobalSection(NestedProjects) = preSolution {9E5A7F49-8E31-4A71-90CC-1DA9AEDA99EE} = {C09CDAB0-6DD4-46E9-B7F3-3EF2A4741EA0} {E8AF8611-0EA4-4B19-BC48-87C57A87DC66} = {9B2AE124-6636-4DE9-83A3-70360DABD0C4} - {96111249-C4C3-4DC9-A887-32D583723AB1} = {9B2AE124-6636-4DE9-83A3-70360DABD0C4} {2F095ED9-5BC9-4512-9013-A47685FB2508} = {3A6B6931-A123-477A-9469-8B468B5385AF} {C42CDE33-0878-4BA0-96F2-4CB7C8FDEAAD} = {9B2AE124-6636-4DE9-83A3-70360DABD0C4} {9961B80E-0718-4280-B2A0-271B003DE26B} = {9B2AE124-6636-4DE9-83A3-70360DABD0C4} {69370370-9873-4D6A-965D-D1E16694047D} = {C09CDAB0-6DD4-46E9-B7F3-3EF2A4741EA0} {F608B509-A99B-4AC7-8227-42051DD4A578} = {C09CDAB0-6DD4-46E9-B7F3-3EF2A4741EA0} + {3B577468-6792-4EF1-9237-15180B176A24} = {9B2AE124-6636-4DE9-83A3-70360DABD0C4} EndGlobalSection EndGlobal diff --git a/samples/Sample.Kafka/AppDbContext.cs b/samples/Sample.Kafka/AppDbContext.cs index fe320e1..fdfd723 100644 --- a/samples/Sample.Kafka/AppDbContext.cs +++ b/samples/Sample.Kafka/AppDbContext.cs @@ -1,20 +1,13 @@ -using System; -using System.Collections.Generic; -using System.Linq; -using System.Threading.Tasks; -using DotNetCore.CAP.EntityFrameworkCore; -using DotNetCore.CAP.Infrastructure; -using JetBrains.Annotations; -using Microsoft.EntityFrameworkCore; +using Microsoft.EntityFrameworkCore; namespace Sample.Kafka { - public class AppDbContext :DbContext + public class AppDbContext : DbContext { protected override void OnConfiguring(DbContextOptionsBuilder optionsBuilder) { - //optionsBuilder.UseSqlServer("Server=192.168.2.206;Initial Catalog=Test;User Id=cmswuliu;Password=h7xY81agBn*Veiu3;MultipleActiveResultSets=True"); - optionsBuilder.UseSqlServer("Server=DESKTOP-M9R8T31;Initial Catalog=Test;User Id=sa;Password=P@ssw0rd;MultipleActiveResultSets=True"); + optionsBuilder.UseSqlServer("Server=192.168.2.206;Initial Catalog=Test;User Id=cmswuliu;Password=h7xY81agBn*Veiu3;MultipleActiveResultSets=True"); + //optionsBuilder.UseSqlServer("Server=DESKTOP-M9R8T31;Initial Catalog=Test;User Id=sa;Password=P@ssw0rd;MultipleActiveResultSets=True"); } } } diff --git a/samples/Sample.Kafka/Controllers/ValuesController.cs b/samples/Sample.Kafka/Controllers/ValuesController.cs index 6ed8a5c..8883225 100644 --- a/samples/Sample.Kafka/Controllers/ValuesController.cs +++ b/samples/Sample.Kafka/Controllers/ValuesController.cs @@ -4,7 +4,6 @@ using DotNetCore.CAP; using DotNetCore.CAP.RabbitMQ; using Microsoft.AspNetCore.Hosting; using Microsoft.AspNetCore.Mvc; -using Dapper; namespace Sample.Kafka.Controllers { diff --git a/samples/Sample.Kafka/Sample.Kafka.csproj b/samples/Sample.Kafka/Sample.Kafka.csproj index 3bb9d98..3788806 100644 --- a/samples/Sample.Kafka/Sample.Kafka.csproj +++ b/samples/Sample.Kafka/Sample.Kafka.csproj @@ -24,8 +24,8 @@ - + diff --git a/samples/Sample.Kafka/Startup.cs b/samples/Sample.Kafka/Startup.cs index a62ba86..5cb3fd8 100644 --- a/samples/Sample.Kafka/Startup.cs +++ b/samples/Sample.Kafka/Startup.cs @@ -28,8 +28,8 @@ namespace Sample.Kafka services.AddCap(x => { x.UseEntityFramework(); - x.UseSqlServer("Server=DESKTOP-M9R8T31;Initial Catalog=Test;User Id=sa;Password=P@ssw0rd;MultipleActiveResultSets=True"); - x.UseRabbitMQ("localhost"); + //x.UseSqlServer("Server=DESKTOP-M9R8T31;Initial Catalog=Test;User Id=sa;Password=P@ssw0rd;MultipleActiveResultSets=True"); + x.UseRabbitMQ(o => { o.HostName = "192.168.2.206"; o.UserName = "admin"; o.Password = "123123"; }); }); // Add framework services. From e2c7d7fdc2a6cbcafc5bb9ec88ea35a1bccacb8b Mon Sep 17 00:00:00 2001 From: yangxiaodong Date: Mon, 17 Jul 2017 17:10:40 +0800 Subject: [PATCH 41/68] fix bug. --- src/DotNetCore.CAP/IConsumerHandler.Default.cs | 1 + 1 file changed, 1 insertion(+) diff --git a/src/DotNetCore.CAP/IConsumerHandler.Default.cs b/src/DotNetCore.CAP/IConsumerHandler.Default.cs index f317b85..6bcf22d 100644 --- a/src/DotNetCore.CAP/IConsumerHandler.Default.cs +++ b/src/DotNetCore.CAP/IConsumerHandler.Default.cs @@ -104,6 +104,7 @@ namespace DotNetCore.CAP var receviedMessage = StoreMessage(scope, message); client.Commit(); } + Pulse(); }; } From d48c2d4f05f5d821af86eadec9116afb0e334a88 Mon Sep 17 00:00:00 2001 From: yangxiaodong Date: Mon, 17 Jul 2017 17:11:00 +0800 Subject: [PATCH 42/68] refactor. --- samples/Sample.Kafka/Controllers/ValuesController.cs | 4 +--- src/DotNetCore.CAP/Infrastructure/Helper.cs | 2 +- src/DotNetCore.CAP/Infrastructure/WebHookProvider.cs | 6 +++++- src/DotNetCore.CAP/Processor/IProcessingServer.Cap.cs | 5 ++--- 4 files changed, 9 insertions(+), 8 deletions(-) diff --git a/samples/Sample.Kafka/Controllers/ValuesController.cs b/samples/Sample.Kafka/Controllers/ValuesController.cs index 8883225..13142a5 100644 --- a/samples/Sample.Kafka/Controllers/ValuesController.cs +++ b/samples/Sample.Kafka/Controllers/ValuesController.cs @@ -29,9 +29,7 @@ namespace Sample.Kafka.Controllers [CapSubscribe("zzwl.topic.finace.callBack", Group = "test")] public void KafkaTest(Person person) { - Console.WriteLine(person.Name); - Console.WriteLine(person.Age); - + Console.WriteLine(DateTime.Now); } [Route("~/send")] diff --git a/src/DotNetCore.CAP/Infrastructure/Helper.cs b/src/DotNetCore.CAP/Infrastructure/Helper.cs index a4c36e2..b3b6c29 100644 --- a/src/DotNetCore.CAP/Infrastructure/Helper.cs +++ b/src/DotNetCore.CAP/Infrastructure/Helper.cs @@ -6,7 +6,7 @@ namespace DotNetCore.CAP.Infrastructure { public static class Helper { - private static readonly DateTime Epoch = new DateTime(1970, 1, 1, 0, 0, 0, DateTimeKind.Utc); + private static readonly DateTime Epoch = new DateTime(1970, 1, 1, 0, 0, 0, DateTimeKind.Local); private static JsonSerializerSettings _serializerSettings; public static void SetSerializerSettings(JsonSerializerSettings setting) diff --git a/src/DotNetCore.CAP/Infrastructure/WebHookProvider.cs b/src/DotNetCore.CAP/Infrastructure/WebHookProvider.cs index 49039f6..d2492dd 100644 --- a/src/DotNetCore.CAP/Infrastructure/WebHookProvider.cs +++ b/src/DotNetCore.CAP/Infrastructure/WebHookProvider.cs @@ -4,7 +4,11 @@ using System.Text; namespace DotNetCore.CAP.Infrastructure { - class WebHookProvider + public class WebHookProvider { + public WebHookProvider() + { + throw new NotImplementedException(); + } } } diff --git a/src/DotNetCore.CAP/Processor/IProcessingServer.Cap.cs b/src/DotNetCore.CAP/Processor/IProcessingServer.Cap.cs index 8aae553..242eff7 100644 --- a/src/DotNetCore.CAP/Processor/IProcessingServer.Cap.cs +++ b/src/DotNetCore.CAP/Processor/IProcessingServer.Cap.cs @@ -59,10 +59,9 @@ namespace DotNetCore.CAP.Processor return; } - _logger.LogTrace("Pulsing the JobQueuer."); + _logger.LogTrace("Pulsing the Queuer."); - PublishQueuer.PulseEvent.Set(); - SubscribeQueuer.PulseEvent.Set(); + PublishQueuer.PulseEvent.Set(); } public void Dispose() From c89c2917f94eb7db10569ac3a6ad565733436439 Mon Sep 17 00:00:00 2001 From: yangxiaodong Date: Mon, 17 Jul 2017 18:29:50 +0800 Subject: [PATCH 43/68] rename namespace. --- .../CapMessageStoreTest.cs | 11 -- .../ConnectionUtil.cs | 47 ----- .../DatabaseTestHost.cs | 62 ------- ...etCore.CAP.EntityFrameworkCore.Test.csproj | 49 ----- .../EFMessageStoreTest.cs | 168 ------------------ .../Properties/AssemblyInfo.cs | 18 -- .../TestHost.cs | 97 ---------- 7 files changed, 452 deletions(-) delete mode 100644 test/DotNetCore.CAP.EntityFrameworkCore.Test/CapMessageStoreTest.cs delete mode 100644 test/DotNetCore.CAP.EntityFrameworkCore.Test/ConnectionUtil.cs delete mode 100644 test/DotNetCore.CAP.EntityFrameworkCore.Test/DatabaseTestHost.cs delete mode 100644 test/DotNetCore.CAP.EntityFrameworkCore.Test/DotNetCore.CAP.EntityFrameworkCore.Test.csproj delete mode 100644 test/DotNetCore.CAP.EntityFrameworkCore.Test/EFMessageStoreTest.cs delete mode 100644 test/DotNetCore.CAP.EntityFrameworkCore.Test/Properties/AssemblyInfo.cs delete mode 100644 test/DotNetCore.CAP.EntityFrameworkCore.Test/TestHost.cs diff --git a/test/DotNetCore.CAP.EntityFrameworkCore.Test/CapMessageStoreTest.cs b/test/DotNetCore.CAP.EntityFrameworkCore.Test/CapMessageStoreTest.cs deleted file mode 100644 index efda431..0000000 --- a/test/DotNetCore.CAP.EntityFrameworkCore.Test/CapMessageStoreTest.cs +++ /dev/null @@ -1,11 +0,0 @@ -using System; -using System.Collections.Generic; -using System.Text; -using Xunit; - -namespace DotNetCore.CAP.EntityFrameworkCore.Test -{ - public class CapMessageStoreTest - { - } -} \ No newline at end of file diff --git a/test/DotNetCore.CAP.EntityFrameworkCore.Test/ConnectionUtil.cs b/test/DotNetCore.CAP.EntityFrameworkCore.Test/ConnectionUtil.cs deleted file mode 100644 index 80fa0c8..0000000 --- a/test/DotNetCore.CAP.EntityFrameworkCore.Test/ConnectionUtil.cs +++ /dev/null @@ -1,47 +0,0 @@ -using System; -using System.Data.SqlClient; - -namespace DotNetCore.CAP.EntityFrameworkCore.Test -{ - public static class ConnectionUtil - { - private const string DatabaseVariable = "Cap_SqlServer_DatabaseName"; - private const string ConnectionStringTemplateVariable = "Cap_SqlServer_ConnectionStringTemplate"; - - private const string MasterDatabaseName = "master"; - private const string DefaultDatabaseName = @"DotNetCore.CAP.EntityFrameworkCore.Test"; - - private const string DefaultConnectionStringTemplate = - @"Server=192.168.2.206;Initial Catalog={0};User Id=sa;Password=123123;MultipleActiveResultSets=True"; - - public static string GetDatabaseName() - { - return Environment.GetEnvironmentVariable(DatabaseVariable) ?? DefaultDatabaseName; - } - - public static string GetMasterConnectionString() - { - return string.Format(GetConnectionStringTemplate(), MasterDatabaseName); - } - - public static string GetConnectionString() - { - return string.Format(GetConnectionStringTemplate(), GetDatabaseName()); - } - - private static string GetConnectionStringTemplate() - { - return - Environment.GetEnvironmentVariable(ConnectionStringTemplateVariable) ?? - DefaultConnectionStringTemplate; - } - - public static SqlConnection CreateConnection(string connectionString = null) - { - connectionString = connectionString ?? GetConnectionString(); - var connection = new SqlConnection(connectionString); - connection.Open(); - return connection; - } - } -} \ No newline at end of file diff --git a/test/DotNetCore.CAP.EntityFrameworkCore.Test/DatabaseTestHost.cs b/test/DotNetCore.CAP.EntityFrameworkCore.Test/DatabaseTestHost.cs deleted file mode 100644 index d6b21b6..0000000 --- a/test/DotNetCore.CAP.EntityFrameworkCore.Test/DatabaseTestHost.cs +++ /dev/null @@ -1,62 +0,0 @@ -using System.Data; -using System.Threading.Tasks; -using Dapper; -using Microsoft.EntityFrameworkCore; - -namespace DotNetCore.CAP.EntityFrameworkCore.Test -{ - //public abstract class DatabaseTestHost : TestHost - //{ - // private static bool _sqlObjectInstalled; - - // protected override void PostBuildServices() - // { - // base.PostBuildServices(); - // InitializeDatabase(); - // } - - // public override void Dispose() - // { - // DeleteAllData(); - // base.Dispose(); - // } - - // private void InitializeDatabase() - // { - // if (!_sqlObjectInstalled) - // { - // using (CreateScope()) - // { - // var context = GetService(); - // context.Database.EnsureDeleted(); - // context.Database.Migrate(); - // _sqlObjectInstalled = true; - // } - // } - // } - - // private void DeleteAllData() - // { - // using (CreateScope()) - // { - // var context = GetService(); - - // var commands = new[] - // { - // "DISABLE TRIGGER ALL ON ?", - // "ALTER TABLE ? NOCHECK CONSTRAINT ALL", - // "DELETE FROM ?", - // "ALTER TABLE ? CHECK CONSTRAINT ALL", - // "ENABLE TRIGGER ALL ON ?" - // }; - // foreach (var command in commands) - // { - // context.Database.GetDbConnection().Execute( - // "sp_MSforeachtable", - // new {command1 = command}, - // commandType: CommandType.StoredProcedure); - // } - // } - // } - //} -} \ No newline at end of file diff --git a/test/DotNetCore.CAP.EntityFrameworkCore.Test/DotNetCore.CAP.EntityFrameworkCore.Test.csproj b/test/DotNetCore.CAP.EntityFrameworkCore.Test/DotNetCore.CAP.EntityFrameworkCore.Test.csproj deleted file mode 100644 index 17da1b0..0000000 --- a/test/DotNetCore.CAP.EntityFrameworkCore.Test/DotNetCore.CAP.EntityFrameworkCore.Test.csproj +++ /dev/null @@ -1,49 +0,0 @@ - - - - netcoreapp1.1 - true - DotNetCore.CAP.EntityFrameworkCore.Test - DotNetCore.CAP.EntityFrameworkCore.Test - true - $(PackageTargetFallback);dnxcore50;portable-net451+win8 - 1.1.1 - false - false - false - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - diff --git a/test/DotNetCore.CAP.EntityFrameworkCore.Test/EFMessageStoreTest.cs b/test/DotNetCore.CAP.EntityFrameworkCore.Test/EFMessageStoreTest.cs deleted file mode 100644 index e59f393..0000000 --- a/test/DotNetCore.CAP.EntityFrameworkCore.Test/EFMessageStoreTest.cs +++ /dev/null @@ -1,168 +0,0 @@ -namespace DotNetCore.CAP.EntityFrameworkCore.Test -{ - //public class EFMessageStoreTest : DatabaseTestHost - //{ - // [Fact] - // public void CanCreateSentMessageUsingEF() - // { - // using (var db = CreateContext()) - // { - // var guid = Guid.NewGuid().ToString(); - // var message = new CapPublishedMessage - // { - // Id = guid, - // Content = "this is message body", - // StatusName = StatusName.Enqueued - // }; - // db.Attach(message).State = Microsoft.EntityFrameworkCore.EntityState.Added; - - // db.SaveChanges(); - - // Assert.True(db.CapSentMessages.Any(u => u.Id == guid)); - // Assert.NotNull(db.CapSentMessages.FirstOrDefault(u => u.StatusName == StatusName.Enqueued)); - // } - // } - - // [Fact] - // public void CanUpdateSentMessageUsingEF() - // { - // using (var db = CreateContext()) - // { - // var guid = Guid.NewGuid().ToString(); - // var message = new CapPublishedMessage - // { - // Id = guid, - // Content = "this is message body", - // StatusName = StatusName.Enqueued - // }; - // db.Attach(message).State = Microsoft.EntityFrameworkCore.EntityState.Added; - - // db.SaveChanges(); - - // var selectedMessage = db.CapSentMessages.FirstOrDefault(u => u.StatusName == StatusName.Enqueued); - // Assert.NotNull(selectedMessage); - - // selectedMessage.StatusName = StatusName.Succeeded; - // selectedMessage.Content = "Test"; - // db.SaveChanges(); - - // selectedMessage = db.CapSentMessages.FirstOrDefault(u => u.StatusName == StatusName.Succeeded); - // Assert.NotNull(selectedMessage); - // Assert.True(selectedMessage.Content == "Test"); - // } - // } - - // [Fact] - // public void CanRemoveSentMessageUsingEF() - // { - // using (var db = CreateContext()) - // { - // var guid = Guid.NewGuid().ToString(); - // var message = new CapPublishedMessage - // { - // Id = guid, - // Content = "this is message body", - // StatusName = StatusName.Enqueued - // }; - // db.Attach(message).State = Microsoft.EntityFrameworkCore.EntityState.Added; - - // db.SaveChanges(); - - // var selectedMessage = db.CapSentMessages.FirstOrDefault(u => u.StatusName == StatusName.Enqueued); - // Assert.NotNull(selectedMessage); - - // db.CapSentMessages.Remove(selectedMessage); - // db.SaveChanges(); - // selectedMessage = db.CapSentMessages.FirstOrDefault(u => u.StatusName == StatusName.Enqueued); - // Assert.Null(selectedMessage); - // } - // } - - // [Fact] - // public void CanCreateReceivedMessageUsingEF() - // { - // using (var db = CreateContext()) - // { - // var guid = Guid.NewGuid().ToString(); - // var message = new CapReceivedMessage - // { - // Id = guid, - // Content = "this is message body", - // StatusName = StatusName.Enqueued - // }; - // db.Attach(message).State = Microsoft.EntityFrameworkCore.EntityState.Added; - - // db.SaveChanges(); - - // Assert.True(db.CapReceivedMessages.Any(u => u.Id == guid)); - // Assert.NotNull(db.CapReceivedMessages.FirstOrDefault(u => u.StatusName == StatusName.Enqueued)); - // } - // } - - // [Fact] - // public void CanUpdateReceivedMessageUsingEF() - // { - // using (var db = CreateContext()) - // { - // var guid = Guid.NewGuid().ToString(); - // var message = new CapReceivedMessage - // { - // Id = guid, - // Content = "this is message body", - // StatusName = StatusName.Enqueued - // }; - // db.Attach(message).State = Microsoft.EntityFrameworkCore.EntityState.Added; - - // db.SaveChanges(); - - // var selectedMessage = db.CapReceivedMessages.FirstOrDefault(u => u.StatusName == StatusName.Enqueued); - // Assert.NotNull(selectedMessage); - - // selectedMessage.StatusName = StatusName.Succeeded; - // selectedMessage.Content = "Test"; - // db.SaveChanges(); - - // selectedMessage = db.CapReceivedMessages.FirstOrDefault(u => u.StatusName == StatusName.Succeeded); - // Assert.NotNull(selectedMessage); - // Assert.True(selectedMessage.Content == "Test"); - // } - // } - - // [Fact] - // public void CanRemoveReceivedMessageUsingEF() - // { - // using (var db = CreateContext()) - // { - // var guid = Guid.NewGuid().ToString(); - // var message = new CapReceivedMessage - // { - // Id = guid, - // Content = "this is message body", - // StatusName = StatusName.Enqueued - // }; - // db.Attach(message).State = Microsoft.EntityFrameworkCore.EntityState.Added; - - // db.SaveChanges(); - - // var selectedMessage = db.CapReceivedMessages.FirstOrDefault(u => u.StatusName == StatusName.Enqueued); - // Assert.NotNull(selectedMessage); - - // db.CapReceivedMessages.Remove(selectedMessage); - // db.SaveChanges(); - // selectedMessage = db.CapReceivedMessages.FirstOrDefault(u => u.StatusName == StatusName.Enqueued); - // Assert.Null(selectedMessage); - // } - // } - - // public TestDbContext CreateContext(bool delete = false) - // { - // var db = Provider.GetRequiredService(); - // if (delete) - // { - // db.Database.EnsureDeleted(); - // } - // db.Database.EnsureCreated(); - // return db; - // } - //} -} \ No newline at end of file diff --git a/test/DotNetCore.CAP.EntityFrameworkCore.Test/Properties/AssemblyInfo.cs b/test/DotNetCore.CAP.EntityFrameworkCore.Test/Properties/AssemblyInfo.cs deleted file mode 100644 index a995715..0000000 --- a/test/DotNetCore.CAP.EntityFrameworkCore.Test/Properties/AssemblyInfo.cs +++ /dev/null @@ -1,18 +0,0 @@ -using System.Reflection; -using System.Runtime.InteropServices; - -// General Information about an assembly is controlled through the following -// set of attributes. Change these attribute values to modify the information -// associated with an assembly. -[assembly: AssemblyConfiguration("")] -[assembly: AssemblyCompany("")] -[assembly: AssemblyProduct("DotNetCore.CAP.EntityFrameworkCore.Test")] -[assembly: AssemblyTrademark("")] - -// Setting ComVisible to false makes the types in this assembly not visible -// to COM components. If you need to access a type in this assembly from -// COM, set the ComVisible attribute to true on that type. -[assembly: ComVisible(false)] - -// The following GUID is for the ID of the typelib if this project is exposed to COM -[assembly: Guid("7442c942-1ddc-40e4-8f1b-654e721eaa45")] \ No newline at end of file diff --git a/test/DotNetCore.CAP.EntityFrameworkCore.Test/TestHost.cs b/test/DotNetCore.CAP.EntityFrameworkCore.Test/TestHost.cs deleted file mode 100644 index fbc1a94..0000000 --- a/test/DotNetCore.CAP.EntityFrameworkCore.Test/TestHost.cs +++ /dev/null @@ -1,97 +0,0 @@ -using System; -using Microsoft.EntityFrameworkCore; -using Microsoft.Extensions.DependencyInjection; - -namespace DotNetCore.CAP.EntityFrameworkCore.Test -{ - public abstract class TestHost : IDisposable - { - protected IServiceCollection _services; - private IServiceProvider _provider; - private IServiceProvider _scopedProvider; - - public TestHost() - { - CreateServiceCollection(); - PreBuildServices(); - BuildServices(); - PostBuildServices(); - } - - protected IServiceProvider Provider => _scopedProvider ?? _provider; - - private void CreateServiceCollection() - { - var services = new ServiceCollection(); - - services.AddOptions(); - services.AddLogging(); - - var connectionString = ConnectionUtil.GetConnectionString(); - //services.AddSingleton(new SqlServerOptions { ConnectionString = connectionString }); - //services.AddDbContext(options => options.UseSqlServer(connectionString)); - - _services = services; - } - - protected virtual void PreBuildServices() - { - } - - private void BuildServices() - { - _provider = _services.BuildServiceProvider(); - } - - protected virtual void PostBuildServices() - { - } - - public IDisposable CreateScope() - { - var scope = CreateScope(_provider); - var loc = scope.ServiceProvider; - _scopedProvider = loc; - return new DelegateDisposable(() => - { - if (_scopedProvider == loc) - { - _scopedProvider = null; - } - scope.Dispose(); - }); - } - - public IServiceScope CreateScope(IServiceProvider provider) - { - var scope = provider.GetService().CreateScope(); - return scope; - } - - public T GetService() => Provider.GetService(); - - public T Ensure(ref T service) - where T : class - => service ?? (service = GetService()); - - public virtual void Dispose() - { - (_provider as IDisposable)?.Dispose(); - } - - private class DelegateDisposable : IDisposable - { - private Action _dispose; - - public DelegateDisposable(Action dispose) - { - _dispose = dispose; - } - - public void Dispose() - { - _dispose(); - } - } - } -} \ No newline at end of file From c4c69a5d145b34bcbebc2d48363de7a01f1da9c8 Mon Sep 17 00:00:00 2001 From: yangxiaodong Date: Mon, 17 Jul 2017 18:30:01 +0800 Subject: [PATCH 44/68] remove unused code. --- src/DotNetCore.CAP/CAP.Builder.cs | 11 ----------- 1 file changed, 11 deletions(-) diff --git a/src/DotNetCore.CAP/CAP.Builder.cs b/src/DotNetCore.CAP/CAP.Builder.cs index 6214c12..e9cf165 100644 --- a/src/DotNetCore.CAP/CAP.Builder.cs +++ b/src/DotNetCore.CAP/CAP.Builder.cs @@ -34,17 +34,6 @@ namespace DotNetCore.CAP return this; } - /// - /// Adds a singleton service of the type specified in serviceType with an implementation - /// - private CapBuilder AddSingleton() - where TService : class - where TImplementation : class, TService - { - Services.AddSingleton(); - return this; - } - /// /// Add an . /// From 93d2e5c372210bfa950786967c02bbd12af8e7d4 Mon Sep 17 00:00:00 2001 From: yangxiaodong Date: Mon, 17 Jul 2017 18:30:27 +0800 Subject: [PATCH 45/68] update UnitTest. --- CAP.sln | 14 +- .../CapMessageStoreTest.cs | 11 ++ .../ConnectionUtil.cs | 47 +++++ .../DatabaseTestHost.cs | 62 +++++++ .../DotNetCore.CAP.SqlServer.Test.csproj | 48 +++++ .../EFMessageStoreTest.cs | 168 ++++++++++++++++++ .../Properties/AssemblyInfo.cs | 18 ++ .../DotNetCore.CAP.SqlServer.Test/TestHost.cs | 97 ++++++++++ test/DotNetCore.CAP.Test/CAP.BuilderTest.cs | 61 +++---- 9 files changed, 487 insertions(+), 39 deletions(-) create mode 100644 test/DotNetCore.CAP.SqlServer.Test/CapMessageStoreTest.cs create mode 100644 test/DotNetCore.CAP.SqlServer.Test/ConnectionUtil.cs create mode 100644 test/DotNetCore.CAP.SqlServer.Test/DatabaseTestHost.cs create mode 100644 test/DotNetCore.CAP.SqlServer.Test/DotNetCore.CAP.SqlServer.Test.csproj create mode 100644 test/DotNetCore.CAP.SqlServer.Test/EFMessageStoreTest.cs create mode 100644 test/DotNetCore.CAP.SqlServer.Test/Properties/AssemblyInfo.cs create mode 100644 test/DotNetCore.CAP.SqlServer.Test/TestHost.cs diff --git a/CAP.sln b/CAP.sln index 5a08718..35a9e3d 100644 --- a/CAP.sln +++ b/CAP.sln @@ -53,12 +53,12 @@ Project("{2150E333-8FDC-42A3-9474-1A3956D46DE8}") = "build", "build", "{10C0818D build\version.props = build\version.props EndProjectSection EndProject -Project("{9A19103F-16F7-4668-BE54-9A1E7A4F7556}") = "DotNetCore.CAP.EntityFrameworkCore.Test", "test\DotNetCore.CAP.EntityFrameworkCore.Test\DotNetCore.CAP.EntityFrameworkCore.Test.csproj", "{69370370-9873-4D6A-965D-D1E16694047D}" -EndProject Project("{9A19103F-16F7-4668-BE54-9A1E7A4F7556}") = "DotNetCore.CAP.Test", "test\DotNetCore.CAP.Test\DotNetCore.CAP.Test.csproj", "{F608B509-A99B-4AC7-8227-42051DD4A578}" EndProject Project("{9A19103F-16F7-4668-BE54-9A1E7A4F7556}") = "DotNetCore.CAP.SqlServer", "src\DotNetCore.CAP.SqlServer\DotNetCore.CAP.SqlServer.csproj", "{3B577468-6792-4EF1-9237-15180B176A24}" EndProject +Project("{9A19103F-16F7-4668-BE54-9A1E7A4F7556}") = "DotNetCore.CAP.SqlServer.Test", "test\DotNetCore.CAP.SqlServer.Test\DotNetCore.CAP.SqlServer.Test.csproj", "{DA00FA38-C4B9-4F55-8756-D480FBC1084F}" +EndProject Global GlobalSection(SolutionConfigurationPlatforms) = preSolution Debug|Any CPU = Debug|Any CPU @@ -81,10 +81,6 @@ Global {9961B80E-0718-4280-B2A0-271B003DE26B}.Debug|Any CPU.Build.0 = Debug|Any CPU {9961B80E-0718-4280-B2A0-271B003DE26B}.Release|Any CPU.ActiveCfg = Release|Any CPU {9961B80E-0718-4280-B2A0-271B003DE26B}.Release|Any CPU.Build.0 = Release|Any CPU - {69370370-9873-4D6A-965D-D1E16694047D}.Debug|Any CPU.ActiveCfg = Debug|Any CPU - {69370370-9873-4D6A-965D-D1E16694047D}.Debug|Any CPU.Build.0 = Debug|Any CPU - {69370370-9873-4D6A-965D-D1E16694047D}.Release|Any CPU.ActiveCfg = Release|Any CPU - {69370370-9873-4D6A-965D-D1E16694047D}.Release|Any CPU.Build.0 = Release|Any CPU {F608B509-A99B-4AC7-8227-42051DD4A578}.Debug|Any CPU.ActiveCfg = Debug|Any CPU {F608B509-A99B-4AC7-8227-42051DD4A578}.Debug|Any CPU.Build.0 = Debug|Any CPU {F608B509-A99B-4AC7-8227-42051DD4A578}.Release|Any CPU.ActiveCfg = Release|Any CPU @@ -92,6 +88,10 @@ Global {3B577468-6792-4EF1-9237-15180B176A24}.Debug|Any CPU.Build.0 = Debug|Any CPU {3B577468-6792-4EF1-9237-15180B176A24}.Release|Any CPU.ActiveCfg = Release|Any CPU {3B577468-6792-4EF1-9237-15180B176A24}.Release|Any CPU.Build.0 = Release|Any CPU + {DA00FA38-C4B9-4F55-8756-D480FBC1084F}.Debug|Any CPU.ActiveCfg = Debug|Any CPU + {DA00FA38-C4B9-4F55-8756-D480FBC1084F}.Debug|Any CPU.Build.0 = Debug|Any CPU + {DA00FA38-C4B9-4F55-8756-D480FBC1084F}.Release|Any CPU.ActiveCfg = Release|Any CPU + {DA00FA38-C4B9-4F55-8756-D480FBC1084F}.Release|Any CPU.Build.0 = Release|Any CPU EndGlobalSection GlobalSection(SolutionProperties) = preSolution HideSolutionNode = FALSE @@ -102,8 +102,8 @@ Global {2F095ED9-5BC9-4512-9013-A47685FB2508} = {3A6B6931-A123-477A-9469-8B468B5385AF} {C42CDE33-0878-4BA0-96F2-4CB7C8FDEAAD} = {9B2AE124-6636-4DE9-83A3-70360DABD0C4} {9961B80E-0718-4280-B2A0-271B003DE26B} = {9B2AE124-6636-4DE9-83A3-70360DABD0C4} - {69370370-9873-4D6A-965D-D1E16694047D} = {C09CDAB0-6DD4-46E9-B7F3-3EF2A4741EA0} {F608B509-A99B-4AC7-8227-42051DD4A578} = {C09CDAB0-6DD4-46E9-B7F3-3EF2A4741EA0} {3B577468-6792-4EF1-9237-15180B176A24} = {9B2AE124-6636-4DE9-83A3-70360DABD0C4} + {DA00FA38-C4B9-4F55-8756-D480FBC1084F} = {C09CDAB0-6DD4-46E9-B7F3-3EF2A4741EA0} EndGlobalSection EndGlobal diff --git a/test/DotNetCore.CAP.SqlServer.Test/CapMessageStoreTest.cs b/test/DotNetCore.CAP.SqlServer.Test/CapMessageStoreTest.cs new file mode 100644 index 0000000..efda431 --- /dev/null +++ b/test/DotNetCore.CAP.SqlServer.Test/CapMessageStoreTest.cs @@ -0,0 +1,11 @@ +using System; +using System.Collections.Generic; +using System.Text; +using Xunit; + +namespace DotNetCore.CAP.EntityFrameworkCore.Test +{ + public class CapMessageStoreTest + { + } +} \ No newline at end of file diff --git a/test/DotNetCore.CAP.SqlServer.Test/ConnectionUtil.cs b/test/DotNetCore.CAP.SqlServer.Test/ConnectionUtil.cs new file mode 100644 index 0000000..80fa0c8 --- /dev/null +++ b/test/DotNetCore.CAP.SqlServer.Test/ConnectionUtil.cs @@ -0,0 +1,47 @@ +using System; +using System.Data.SqlClient; + +namespace DotNetCore.CAP.EntityFrameworkCore.Test +{ + public static class ConnectionUtil + { + private const string DatabaseVariable = "Cap_SqlServer_DatabaseName"; + private const string ConnectionStringTemplateVariable = "Cap_SqlServer_ConnectionStringTemplate"; + + private const string MasterDatabaseName = "master"; + private const string DefaultDatabaseName = @"DotNetCore.CAP.EntityFrameworkCore.Test"; + + private const string DefaultConnectionStringTemplate = + @"Server=192.168.2.206;Initial Catalog={0};User Id=sa;Password=123123;MultipleActiveResultSets=True"; + + public static string GetDatabaseName() + { + return Environment.GetEnvironmentVariable(DatabaseVariable) ?? DefaultDatabaseName; + } + + public static string GetMasterConnectionString() + { + return string.Format(GetConnectionStringTemplate(), MasterDatabaseName); + } + + public static string GetConnectionString() + { + return string.Format(GetConnectionStringTemplate(), GetDatabaseName()); + } + + private static string GetConnectionStringTemplate() + { + return + Environment.GetEnvironmentVariable(ConnectionStringTemplateVariable) ?? + DefaultConnectionStringTemplate; + } + + public static SqlConnection CreateConnection(string connectionString = null) + { + connectionString = connectionString ?? GetConnectionString(); + var connection = new SqlConnection(connectionString); + connection.Open(); + return connection; + } + } +} \ No newline at end of file diff --git a/test/DotNetCore.CAP.SqlServer.Test/DatabaseTestHost.cs b/test/DotNetCore.CAP.SqlServer.Test/DatabaseTestHost.cs new file mode 100644 index 0000000..d6b21b6 --- /dev/null +++ b/test/DotNetCore.CAP.SqlServer.Test/DatabaseTestHost.cs @@ -0,0 +1,62 @@ +using System.Data; +using System.Threading.Tasks; +using Dapper; +using Microsoft.EntityFrameworkCore; + +namespace DotNetCore.CAP.EntityFrameworkCore.Test +{ + //public abstract class DatabaseTestHost : TestHost + //{ + // private static bool _sqlObjectInstalled; + + // protected override void PostBuildServices() + // { + // base.PostBuildServices(); + // InitializeDatabase(); + // } + + // public override void Dispose() + // { + // DeleteAllData(); + // base.Dispose(); + // } + + // private void InitializeDatabase() + // { + // if (!_sqlObjectInstalled) + // { + // using (CreateScope()) + // { + // var context = GetService(); + // context.Database.EnsureDeleted(); + // context.Database.Migrate(); + // _sqlObjectInstalled = true; + // } + // } + // } + + // private void DeleteAllData() + // { + // using (CreateScope()) + // { + // var context = GetService(); + + // var commands = new[] + // { + // "DISABLE TRIGGER ALL ON ?", + // "ALTER TABLE ? NOCHECK CONSTRAINT ALL", + // "DELETE FROM ?", + // "ALTER TABLE ? CHECK CONSTRAINT ALL", + // "ENABLE TRIGGER ALL ON ?" + // }; + // foreach (var command in commands) + // { + // context.Database.GetDbConnection().Execute( + // "sp_MSforeachtable", + // new {command1 = command}, + // commandType: CommandType.StoredProcedure); + // } + // } + // } + //} +} \ No newline at end of file diff --git a/test/DotNetCore.CAP.SqlServer.Test/DotNetCore.CAP.SqlServer.Test.csproj b/test/DotNetCore.CAP.SqlServer.Test/DotNetCore.CAP.SqlServer.Test.csproj new file mode 100644 index 0000000..177d825 --- /dev/null +++ b/test/DotNetCore.CAP.SqlServer.Test/DotNetCore.CAP.SqlServer.Test.csproj @@ -0,0 +1,48 @@ + + + + netcoreapp1.1 + true + DotNetCore.CAP.SqlServer.Test + DotNetCore.CAP.SqlServer.Test + true + $(PackageTargetFallback);dnxcore50;portable-net451+win8 + 1.1.1 + false + false + false + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + diff --git a/test/DotNetCore.CAP.SqlServer.Test/EFMessageStoreTest.cs b/test/DotNetCore.CAP.SqlServer.Test/EFMessageStoreTest.cs new file mode 100644 index 0000000..e59f393 --- /dev/null +++ b/test/DotNetCore.CAP.SqlServer.Test/EFMessageStoreTest.cs @@ -0,0 +1,168 @@ +namespace DotNetCore.CAP.EntityFrameworkCore.Test +{ + //public class EFMessageStoreTest : DatabaseTestHost + //{ + // [Fact] + // public void CanCreateSentMessageUsingEF() + // { + // using (var db = CreateContext()) + // { + // var guid = Guid.NewGuid().ToString(); + // var message = new CapPublishedMessage + // { + // Id = guid, + // Content = "this is message body", + // StatusName = StatusName.Enqueued + // }; + // db.Attach(message).State = Microsoft.EntityFrameworkCore.EntityState.Added; + + // db.SaveChanges(); + + // Assert.True(db.CapSentMessages.Any(u => u.Id == guid)); + // Assert.NotNull(db.CapSentMessages.FirstOrDefault(u => u.StatusName == StatusName.Enqueued)); + // } + // } + + // [Fact] + // public void CanUpdateSentMessageUsingEF() + // { + // using (var db = CreateContext()) + // { + // var guid = Guid.NewGuid().ToString(); + // var message = new CapPublishedMessage + // { + // Id = guid, + // Content = "this is message body", + // StatusName = StatusName.Enqueued + // }; + // db.Attach(message).State = Microsoft.EntityFrameworkCore.EntityState.Added; + + // db.SaveChanges(); + + // var selectedMessage = db.CapSentMessages.FirstOrDefault(u => u.StatusName == StatusName.Enqueued); + // Assert.NotNull(selectedMessage); + + // selectedMessage.StatusName = StatusName.Succeeded; + // selectedMessage.Content = "Test"; + // db.SaveChanges(); + + // selectedMessage = db.CapSentMessages.FirstOrDefault(u => u.StatusName == StatusName.Succeeded); + // Assert.NotNull(selectedMessage); + // Assert.True(selectedMessage.Content == "Test"); + // } + // } + + // [Fact] + // public void CanRemoveSentMessageUsingEF() + // { + // using (var db = CreateContext()) + // { + // var guid = Guid.NewGuid().ToString(); + // var message = new CapPublishedMessage + // { + // Id = guid, + // Content = "this is message body", + // StatusName = StatusName.Enqueued + // }; + // db.Attach(message).State = Microsoft.EntityFrameworkCore.EntityState.Added; + + // db.SaveChanges(); + + // var selectedMessage = db.CapSentMessages.FirstOrDefault(u => u.StatusName == StatusName.Enqueued); + // Assert.NotNull(selectedMessage); + + // db.CapSentMessages.Remove(selectedMessage); + // db.SaveChanges(); + // selectedMessage = db.CapSentMessages.FirstOrDefault(u => u.StatusName == StatusName.Enqueued); + // Assert.Null(selectedMessage); + // } + // } + + // [Fact] + // public void CanCreateReceivedMessageUsingEF() + // { + // using (var db = CreateContext()) + // { + // var guid = Guid.NewGuid().ToString(); + // var message = new CapReceivedMessage + // { + // Id = guid, + // Content = "this is message body", + // StatusName = StatusName.Enqueued + // }; + // db.Attach(message).State = Microsoft.EntityFrameworkCore.EntityState.Added; + + // db.SaveChanges(); + + // Assert.True(db.CapReceivedMessages.Any(u => u.Id == guid)); + // Assert.NotNull(db.CapReceivedMessages.FirstOrDefault(u => u.StatusName == StatusName.Enqueued)); + // } + // } + + // [Fact] + // public void CanUpdateReceivedMessageUsingEF() + // { + // using (var db = CreateContext()) + // { + // var guid = Guid.NewGuid().ToString(); + // var message = new CapReceivedMessage + // { + // Id = guid, + // Content = "this is message body", + // StatusName = StatusName.Enqueued + // }; + // db.Attach(message).State = Microsoft.EntityFrameworkCore.EntityState.Added; + + // db.SaveChanges(); + + // var selectedMessage = db.CapReceivedMessages.FirstOrDefault(u => u.StatusName == StatusName.Enqueued); + // Assert.NotNull(selectedMessage); + + // selectedMessage.StatusName = StatusName.Succeeded; + // selectedMessage.Content = "Test"; + // db.SaveChanges(); + + // selectedMessage = db.CapReceivedMessages.FirstOrDefault(u => u.StatusName == StatusName.Succeeded); + // Assert.NotNull(selectedMessage); + // Assert.True(selectedMessage.Content == "Test"); + // } + // } + + // [Fact] + // public void CanRemoveReceivedMessageUsingEF() + // { + // using (var db = CreateContext()) + // { + // var guid = Guid.NewGuid().ToString(); + // var message = new CapReceivedMessage + // { + // Id = guid, + // Content = "this is message body", + // StatusName = StatusName.Enqueued + // }; + // db.Attach(message).State = Microsoft.EntityFrameworkCore.EntityState.Added; + + // db.SaveChanges(); + + // var selectedMessage = db.CapReceivedMessages.FirstOrDefault(u => u.StatusName == StatusName.Enqueued); + // Assert.NotNull(selectedMessage); + + // db.CapReceivedMessages.Remove(selectedMessage); + // db.SaveChanges(); + // selectedMessage = db.CapReceivedMessages.FirstOrDefault(u => u.StatusName == StatusName.Enqueued); + // Assert.Null(selectedMessage); + // } + // } + + // public TestDbContext CreateContext(bool delete = false) + // { + // var db = Provider.GetRequiredService(); + // if (delete) + // { + // db.Database.EnsureDeleted(); + // } + // db.Database.EnsureCreated(); + // return db; + // } + //} +} \ No newline at end of file diff --git a/test/DotNetCore.CAP.SqlServer.Test/Properties/AssemblyInfo.cs b/test/DotNetCore.CAP.SqlServer.Test/Properties/AssemblyInfo.cs new file mode 100644 index 0000000..a995715 --- /dev/null +++ b/test/DotNetCore.CAP.SqlServer.Test/Properties/AssemblyInfo.cs @@ -0,0 +1,18 @@ +using System.Reflection; +using System.Runtime.InteropServices; + +// General Information about an assembly is controlled through the following +// set of attributes. Change these attribute values to modify the information +// associated with an assembly. +[assembly: AssemblyConfiguration("")] +[assembly: AssemblyCompany("")] +[assembly: AssemblyProduct("DotNetCore.CAP.EntityFrameworkCore.Test")] +[assembly: AssemblyTrademark("")] + +// Setting ComVisible to false makes the types in this assembly not visible +// to COM components. If you need to access a type in this assembly from +// COM, set the ComVisible attribute to true on that type. +[assembly: ComVisible(false)] + +// The following GUID is for the ID of the typelib if this project is exposed to COM +[assembly: Guid("7442c942-1ddc-40e4-8f1b-654e721eaa45")] \ No newline at end of file diff --git a/test/DotNetCore.CAP.SqlServer.Test/TestHost.cs b/test/DotNetCore.CAP.SqlServer.Test/TestHost.cs new file mode 100644 index 0000000..fbc1a94 --- /dev/null +++ b/test/DotNetCore.CAP.SqlServer.Test/TestHost.cs @@ -0,0 +1,97 @@ +using System; +using Microsoft.EntityFrameworkCore; +using Microsoft.Extensions.DependencyInjection; + +namespace DotNetCore.CAP.EntityFrameworkCore.Test +{ + public abstract class TestHost : IDisposable + { + protected IServiceCollection _services; + private IServiceProvider _provider; + private IServiceProvider _scopedProvider; + + public TestHost() + { + CreateServiceCollection(); + PreBuildServices(); + BuildServices(); + PostBuildServices(); + } + + protected IServiceProvider Provider => _scopedProvider ?? _provider; + + private void CreateServiceCollection() + { + var services = new ServiceCollection(); + + services.AddOptions(); + services.AddLogging(); + + var connectionString = ConnectionUtil.GetConnectionString(); + //services.AddSingleton(new SqlServerOptions { ConnectionString = connectionString }); + //services.AddDbContext(options => options.UseSqlServer(connectionString)); + + _services = services; + } + + protected virtual void PreBuildServices() + { + } + + private void BuildServices() + { + _provider = _services.BuildServiceProvider(); + } + + protected virtual void PostBuildServices() + { + } + + public IDisposable CreateScope() + { + var scope = CreateScope(_provider); + var loc = scope.ServiceProvider; + _scopedProvider = loc; + return new DelegateDisposable(() => + { + if (_scopedProvider == loc) + { + _scopedProvider = null; + } + scope.Dispose(); + }); + } + + public IServiceScope CreateScope(IServiceProvider provider) + { + var scope = provider.GetService().CreateScope(); + return scope; + } + + public T GetService() => Provider.GetService(); + + public T Ensure(ref T service) + where T : class + => service ?? (service = GetService()); + + public virtual void Dispose() + { + (_provider as IDisposable)?.Dispose(); + } + + private class DelegateDisposable : IDisposable + { + private Action _dispose; + + public DelegateDisposable(Action dispose) + { + _dispose = dispose; + } + + public void Dispose() + { + _dispose(); + } + } + } +} \ No newline at end of file diff --git a/test/DotNetCore.CAP.Test/CAP.BuilderTest.cs b/test/DotNetCore.CAP.Test/CAP.BuilderTest.cs index 282b36d..d63f25d 100644 --- a/test/DotNetCore.CAP.Test/CAP.BuilderTest.cs +++ b/test/DotNetCore.CAP.Test/CAP.BuilderTest.cs @@ -1,8 +1,5 @@ using System; -using System.Threading; using System.Threading.Tasks; -using DotNetCore.CAP.Processor; -using DotNetCore.CAP.Models; using Microsoft.Extensions.DependencyInjection; using Xunit; using System.Data; @@ -11,42 +8,42 @@ namespace DotNetCore.CAP.Test { public class CapBuilderTest { - //[Fact] - //public void CanOverrideMessageStore() - //{ - // var services = new ServiceCollection(); - // services.AddCap().AddMessageStore(); - // var thingy = services.BuildServiceProvider() - // .GetRequiredService() as MyMessageStore; - - // Assert.NotNull(thingy); - ////} + [Fact] + public void CanCreateInstanceAndGetService() + { + var services = new ServiceCollection(); + services.AddSingleton(); + var builder = new CapBuilder(services); + Assert.NotNull(builder); - //[Fact] - //public void CanOverrideJobs() - //{ - // var services = new ServiceCollection(); - // services.AddCap().AddJobs(); + var count = builder.Services.Count; + Assert.Equal(1, count); + } - // var thingy = services.BuildServiceProvider() - // .GetRequiredService() as MyJobTest; + [Fact] + public void CanAddCapService() + { + var services = new ServiceCollection(); + services.AddCap(x => { }); + var builder = services.BuildServiceProvider(); - // Assert.NotNull(thingy); - //} + var markService = builder.GetService(); + Assert.NotNull(markService); + } - //[Fact] - //public void CanOverrideProducerService() - //{ - // var services = new ServiceCollection(); - // services.AddCap(x=> { }); - // var thingy = services.BuildServiceProvider() - // .GetRequiredService() as MyProducerService; + [Fact] + public void CanOverridePublishService() + { + var services = new ServiceCollection(); + services.AddCap(x => { }).AddProducerService(); - // Assert.NotNull(thingy); - //} + var thingy = services.BuildServiceProvider() + .GetRequiredService() as MyProducerService; + Assert.NotNull(thingy); + } private class MyProducerService : ICapPublisher { @@ -69,6 +66,6 @@ namespace DotNetCore.CAP.Test { throw new NotImplementedException(); } - } + } } } \ No newline at end of file From c1db4267b2f1ed803060055878460c5e74e43802 Mon Sep 17 00:00:00 2001 From: Savorboard Date: Tue, 18 Jul 2017 00:29:47 +0800 Subject: [PATCH 46/68] rename method. --- src/DotNetCore.CAP/CAP.ServiceCollectionExtensions.cs | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/src/DotNetCore.CAP/CAP.ServiceCollectionExtensions.cs b/src/DotNetCore.CAP/CAP.ServiceCollectionExtensions.cs index e025ea6..7e3908d 100644 --- a/src/DotNetCore.CAP/CAP.ServiceCollectionExtensions.cs +++ b/src/DotNetCore.CAP/CAP.ServiceCollectionExtensions.cs @@ -32,7 +32,7 @@ namespace Microsoft.Extensions.DependencyInjection services.TryAddSingleton(); services.Configure(setupAction); - AddConsumerServices(services); + AddSubscribeServices(services); services.TryAddSingleton(); services.TryAddSingleton(); @@ -65,7 +65,7 @@ namespace Microsoft.Extensions.DependencyInjection return new CapBuilder(services); } - private static void AddConsumerServices(IServiceCollection services) + private static void AddSubscribeServices(IServiceCollection services) { var consumerListenerServices = new Dictionary(); foreach (var rejectedServices in services) From e72cc784e6b904f3f146f9c844209ab6dc88831b Mon Sep 17 00:00:00 2001 From: Savorboard Date: Tue, 18 Jul 2017 00:29:54 +0800 Subject: [PATCH 47/68] add unit tests. --- .../CapMessageStoreTest.cs | 11 -- .../ConnectionUtil.cs | 2 +- .../DatabaseTestHost.cs | 102 +++++++++--------- .../TestDbContext.cs | 13 +++ .../DotNetCore.CAP.SqlServer.Test/TestHost.cs | 7 +- test/DotNetCore.CAP.Test/CAP.BuilderTest.cs | 16 ++- .../ConsistencyOptionsTest.cs | 6 -- test/DotNetCore.CAP.Test/NoopMessageStore.cs | 21 ---- test/DotNetCore.CAP.Test/StateChangerTest.cs | 59 ++++++++++ 9 files changed, 143 insertions(+), 94 deletions(-) delete mode 100644 test/DotNetCore.CAP.SqlServer.Test/CapMessageStoreTest.cs create mode 100644 test/DotNetCore.CAP.SqlServer.Test/TestDbContext.cs delete mode 100644 test/DotNetCore.CAP.Test/ConsistencyOptionsTest.cs delete mode 100644 test/DotNetCore.CAP.Test/NoopMessageStore.cs create mode 100644 test/DotNetCore.CAP.Test/StateChangerTest.cs diff --git a/test/DotNetCore.CAP.SqlServer.Test/CapMessageStoreTest.cs b/test/DotNetCore.CAP.SqlServer.Test/CapMessageStoreTest.cs deleted file mode 100644 index efda431..0000000 --- a/test/DotNetCore.CAP.SqlServer.Test/CapMessageStoreTest.cs +++ /dev/null @@ -1,11 +0,0 @@ -using System; -using System.Collections.Generic; -using System.Text; -using Xunit; - -namespace DotNetCore.CAP.EntityFrameworkCore.Test -{ - public class CapMessageStoreTest - { - } -} \ No newline at end of file diff --git a/test/DotNetCore.CAP.SqlServer.Test/ConnectionUtil.cs b/test/DotNetCore.CAP.SqlServer.Test/ConnectionUtil.cs index 80fa0c8..c9ba0b5 100644 --- a/test/DotNetCore.CAP.SqlServer.Test/ConnectionUtil.cs +++ b/test/DotNetCore.CAP.SqlServer.Test/ConnectionUtil.cs @@ -1,7 +1,7 @@ using System; using System.Data.SqlClient; -namespace DotNetCore.CAP.EntityFrameworkCore.Test +namespace DotNetCore.CAP.SqlServer.Test { public static class ConnectionUtil { diff --git a/test/DotNetCore.CAP.SqlServer.Test/DatabaseTestHost.cs b/test/DotNetCore.CAP.SqlServer.Test/DatabaseTestHost.cs index d6b21b6..380a55b 100644 --- a/test/DotNetCore.CAP.SqlServer.Test/DatabaseTestHost.cs +++ b/test/DotNetCore.CAP.SqlServer.Test/DatabaseTestHost.cs @@ -1,62 +1,62 @@ using System.Data; -using System.Threading.Tasks; +using System.Threading; using Dapper; using Microsoft.EntityFrameworkCore; -namespace DotNetCore.CAP.EntityFrameworkCore.Test +namespace DotNetCore.CAP.SqlServer.Test { - //public abstract class DatabaseTestHost : TestHost - //{ - // private static bool _sqlObjectInstalled; + public abstract class DatabaseTestHost : TestHost + { + private static bool _sqlObjectInstalled; - // protected override void PostBuildServices() - // { - // base.PostBuildServices(); - // InitializeDatabase(); - // } + protected override void PostBuildServices() + { + base.PostBuildServices(); + InitializeDatabase(); + } - // public override void Dispose() - // { - // DeleteAllData(); - // base.Dispose(); - // } + public override void Dispose() + { + DeleteAllData(); + base.Dispose(); + } - // private void InitializeDatabase() - // { - // if (!_sqlObjectInstalled) - // { - // using (CreateScope()) - // { - // var context = GetService(); - // context.Database.EnsureDeleted(); - // context.Database.Migrate(); - // _sqlObjectInstalled = true; - // } - // } - // } + private void InitializeDatabase() + { + if (!_sqlObjectInstalled) + { + using (CreateScope()) + { + var storage = GetService(); + var token = new CancellationTokenSource().Token; + storage.InitializeAsync(token).Wait(); + _sqlObjectInstalled = true; + } + } + } - // private void DeleteAllData() - // { - // using (CreateScope()) - // { - // var context = GetService(); + private void DeleteAllData() + { + using (CreateScope()) + { + var context = GetService(); - // var commands = new[] - // { - // "DISABLE TRIGGER ALL ON ?", - // "ALTER TABLE ? NOCHECK CONSTRAINT ALL", - // "DELETE FROM ?", - // "ALTER TABLE ? CHECK CONSTRAINT ALL", - // "ENABLE TRIGGER ALL ON ?" - // }; - // foreach (var command in commands) - // { - // context.Database.GetDbConnection().Execute( - // "sp_MSforeachtable", - // new {command1 = command}, - // commandType: CommandType.StoredProcedure); - // } - // } - // } - //} + var commands = new[] + { + "DISABLE TRIGGER ALL ON ?", + "ALTER TABLE ? NOCHECK CONSTRAINT ALL", + "DELETE FROM ?", + "ALTER TABLE ? CHECK CONSTRAINT ALL", + "ENABLE TRIGGER ALL ON ?" + }; + foreach (var command in commands) + { + context.Database.GetDbConnection().Execute( + "sp_MSforeachtable", + new { command1 = command }, + commandType: CommandType.StoredProcedure); + } + } + } + } } \ No newline at end of file diff --git a/test/DotNetCore.CAP.SqlServer.Test/TestDbContext.cs b/test/DotNetCore.CAP.SqlServer.Test/TestDbContext.cs new file mode 100644 index 0000000..d59bdf1 --- /dev/null +++ b/test/DotNetCore.CAP.SqlServer.Test/TestDbContext.cs @@ -0,0 +1,13 @@ +using Microsoft.EntityFrameworkCore; + +namespace DotNetCore.CAP.SqlServer.Test +{ + public class TestDbContext : DbContext + { + protected override void OnConfiguring(DbContextOptionsBuilder optionsBuilder) + { + var connectionString = ConnectionUtil.GetConnectionString(); + optionsBuilder.UseSqlServer(connectionString); + } + } +} \ No newline at end of file diff --git a/test/DotNetCore.CAP.SqlServer.Test/TestHost.cs b/test/DotNetCore.CAP.SqlServer.Test/TestHost.cs index fbc1a94..3b218fc 100644 --- a/test/DotNetCore.CAP.SqlServer.Test/TestHost.cs +++ b/test/DotNetCore.CAP.SqlServer.Test/TestHost.cs @@ -2,7 +2,7 @@ using System; using Microsoft.EntityFrameworkCore; using Microsoft.Extensions.DependencyInjection; -namespace DotNetCore.CAP.EntityFrameworkCore.Test +namespace DotNetCore.CAP.SqlServer.Test { public abstract class TestHost : IDisposable { @@ -28,8 +28,9 @@ namespace DotNetCore.CAP.EntityFrameworkCore.Test services.AddLogging(); var connectionString = ConnectionUtil.GetConnectionString(); - //services.AddSingleton(new SqlServerOptions { ConnectionString = connectionString }); - //services.AddDbContext(options => options.UseSqlServer(connectionString)); + services.AddSingleton(new SqlServerOptions { ConnectionString = connectionString }); + services.AddSingleton(); + services.AddDbContext(options => options.UseSqlServer(connectionString)); _services = services; } diff --git a/test/DotNetCore.CAP.Test/CAP.BuilderTest.cs b/test/DotNetCore.CAP.Test/CAP.BuilderTest.cs index d63f25d..2b18691 100644 --- a/test/DotNetCore.CAP.Test/CAP.BuilderTest.cs +++ b/test/DotNetCore.CAP.Test/CAP.BuilderTest.cs @@ -8,17 +8,21 @@ namespace DotNetCore.CAP.Test { public class CapBuilderTest { - [Fact] public void CanCreateInstanceAndGetService() { var services = new ServiceCollection(); + services.AddSingleton(); var builder = new CapBuilder(services); Assert.NotNull(builder); var count = builder.Services.Count; Assert.Equal(1, count); + + var provider = services.BuildServiceProvider(); + var capPublisher = provider.GetService(); + Assert.NotNull(capPublisher); } [Fact] @@ -45,6 +49,16 @@ namespace DotNetCore.CAP.Test Assert.NotNull(thingy); } + [Fact] + public void CanResolveCapOptions() + { + var services = new ServiceCollection(); + services.AddCap(x => { }); + var builder = services.BuildServiceProvider(); + var capOptions = builder.GetService(); + Assert.NotNull(capOptions); + } + private class MyProducerService : ICapPublisher { public Task PublishAsync(string topic, string content) diff --git a/test/DotNetCore.CAP.Test/ConsistencyOptionsTest.cs b/test/DotNetCore.CAP.Test/ConsistencyOptionsTest.cs deleted file mode 100644 index b9484aa..0000000 --- a/test/DotNetCore.CAP.Test/ConsistencyOptionsTest.cs +++ /dev/null @@ -1,6 +0,0 @@ -namespace CDotNetCore.CAPTest -{ - public class ConsistencyOptionsTest - { - } -} \ No newline at end of file diff --git a/test/DotNetCore.CAP.Test/NoopMessageStore.cs b/test/DotNetCore.CAP.Test/NoopMessageStore.cs deleted file mode 100644 index 97cb6a7..0000000 --- a/test/DotNetCore.CAP.Test/NoopMessageStore.cs +++ /dev/null @@ -1,21 +0,0 @@ -using System; -using System.Threading; -using System.Threading.Tasks; -using DotNetCore.CAP.Models; - -namespace DotNetCore.CAP.Test -{ - //public class NoopMessageStore : ICapMessageStore - //{ - // public Task ChangeReceivedMessageStateAsync(CapReceivedMessage message, string statusName, - // bool autoSaveChanges = true) - // { - // throw new NotImplementedException(); - // } - - // public Task StoreSentMessageAsync(CapSentMessage message) - // { - // throw new NotImplementedException(); - // } - //} -} \ No newline at end of file diff --git a/test/DotNetCore.CAP.Test/StateChangerTest.cs b/test/DotNetCore.CAP.Test/StateChangerTest.cs new file mode 100644 index 0000000..51101bd --- /dev/null +++ b/test/DotNetCore.CAP.Test/StateChangerTest.cs @@ -0,0 +1,59 @@ +using System; +using DotNetCore.CAP.Infrastructure; +using DotNetCore.CAP.Models; +using DotNetCore.CAP.Processor.States; +using Moq; +using Xunit; + +namespace DotNetCore.CAP.Test +{ + public class StateChangerTest + { + [Fact] + public void ChangeState() + { + // Arrange + var fixture = Create(); + var message = new CapPublishedMessage + { + StatusName = StatusName.Enqueued + }; + var state = Mock.Of(s => s.Name == "s" && s.ExpiresAfter == null); + var mockTransaction = new Mock(); + + // Act + fixture.ChangeState(message, state, mockTransaction.Object); + + // Assert + Assert.Equal(message.StatusName, "s"); + Assert.Null(message.ExpiresAt); + Mock.Get(state).Verify(s => s.Apply(message, mockTransaction.Object), Times.Once); + mockTransaction.Verify(t => t.UpdateMessage(message), Times.Once); + mockTransaction.Verify(t => t.CommitAsync(), Times.Never); + } + + [Fact] + public void ChangeState_ExpiresAfter() + { + // Arrange + var fixture = Create(); + var message = new CapPublishedMessage + { + StatusName = StatusName.Enqueued + }; + var state = Mock.Of(s => s.Name == "s" && s.ExpiresAfter == TimeSpan.FromHours(1)); + var mockTransaction = new Mock(); + + // Act + fixture.ChangeState(message, state, mockTransaction.Object); + + // Assert + Assert.Equal(message.StatusName, "s"); + Assert.NotNull(message.ExpiresAt); + mockTransaction.Verify(t => t.UpdateMessage(message), Times.Once); + mockTransaction.Verify(t => t.CommitAsync(), Times.Never); + } + + private StateChanger Create() => new StateChanger(); + } +} From d227be5bd08821a055435972f81d41939b901a11 Mon Sep 17 00:00:00 2001 From: yangxiaodong Date: Tue, 18 Jul 2017 14:24:49 +0800 Subject: [PATCH 48/68] rename. --- .../Internal/{DefaultModelBinder.cs => IModelBinder.Default.cs} | 0 1 file changed, 0 insertions(+), 0 deletions(-) rename src/DotNetCore.CAP/Internal/{DefaultModelBinder.cs => IModelBinder.Default.cs} (100%) diff --git a/src/DotNetCore.CAP/Internal/DefaultModelBinder.cs b/src/DotNetCore.CAP/Internal/IModelBinder.Default.cs similarity index 100% rename from src/DotNetCore.CAP/Internal/DefaultModelBinder.cs rename to src/DotNetCore.CAP/Internal/IModelBinder.Default.cs From d2dbb1e572abcf9361e6542f3053bf53e5f714a3 Mon Sep 17 00:00:00 2001 From: yangxiaodong Date: Tue, 18 Jul 2017 14:25:16 +0800 Subject: [PATCH 49/68] move namespace. --- .../{Infrastructure => Internal}/IConsumerInvokerFactory.cs | 2 +- src/DotNetCore.CAP/{Infrastructure => }/MessageContext.cs | 2 +- 2 files changed, 2 insertions(+), 2 deletions(-) rename src/DotNetCore.CAP/{Infrastructure => Internal}/IConsumerInvokerFactory.cs (80%) rename src/DotNetCore.CAP/{Infrastructure => }/MessageContext.cs (79%) diff --git a/src/DotNetCore.CAP/Infrastructure/IConsumerInvokerFactory.cs b/src/DotNetCore.CAP/Internal/IConsumerInvokerFactory.cs similarity index 80% rename from src/DotNetCore.CAP/Infrastructure/IConsumerInvokerFactory.cs rename to src/DotNetCore.CAP/Internal/IConsumerInvokerFactory.cs index de2153b..561c99c 100644 --- a/src/DotNetCore.CAP/Infrastructure/IConsumerInvokerFactory.cs +++ b/src/DotNetCore.CAP/Internal/IConsumerInvokerFactory.cs @@ -1,6 +1,6 @@ using DotNetCore.CAP.Abstractions; -namespace DotNetCore.CAP.Infrastructure +namespace DotNetCore.CAP.Internal { public interface IConsumerInvokerFactory { diff --git a/src/DotNetCore.CAP/Infrastructure/MessageContext.cs b/src/DotNetCore.CAP/MessageContext.cs similarity index 79% rename from src/DotNetCore.CAP/Infrastructure/MessageContext.cs rename to src/DotNetCore.CAP/MessageContext.cs index 6f8dfe8..9e1f867 100644 --- a/src/DotNetCore.CAP/Infrastructure/MessageContext.cs +++ b/src/DotNetCore.CAP/MessageContext.cs @@ -1,4 +1,4 @@ -namespace DotNetCore.CAP.Infrastructure +namespace DotNetCore.CAP { public class MessageContext { From 223430ced27267f305dc96677336811a71a20ece Mon Sep 17 00:00:00 2001 From: yangxiaodong Date: Tue, 18 Jul 2017 14:26:04 +0800 Subject: [PATCH 50/68] rename method. --- src/DotNetCore.CAP/IQueueExecutor.Publish.Base.cs | 4 ++-- src/DotNetCore.CAP/IQueueExecutor.Subscibe.cs | 8 ++------ 2 files changed, 4 insertions(+), 8 deletions(-) diff --git a/src/DotNetCore.CAP/IQueueExecutor.Publish.Base.cs b/src/DotNetCore.CAP/IQueueExecutor.Publish.Base.cs index 27742ab..a032af6 100644 --- a/src/DotNetCore.CAP/IQueueExecutor.Publish.Base.cs +++ b/src/DotNetCore.CAP/IQueueExecutor.Publish.Base.cs @@ -40,7 +40,7 @@ namespace DotNetCore.CAP var newState = default(IState); if (!result.Succeeded) { - var shouldRetry = await UpdateJobForRetryAsync(message, connection); + var shouldRetry = await UpdateMessageForRetryAsync(message, connection); if (shouldRetry) { newState = new ScheduledState(); @@ -74,7 +74,7 @@ namespace DotNetCore.CAP } } - private async Task UpdateJobForRetryAsync(CapPublishedMessage message, IStorageConnection connection) + private async Task UpdateMessageForRetryAsync(CapPublishedMessage message, IStorageConnection connection) { var retryBehavior = RetryBehavior.DefaultRetry; diff --git a/src/DotNetCore.CAP/IQueueExecutor.Subscibe.cs b/src/DotNetCore.CAP/IQueueExecutor.Subscibe.cs index 6ea5095..e335637 100644 --- a/src/DotNetCore.CAP/IQueueExecutor.Subscibe.cs +++ b/src/DotNetCore.CAP/IQueueExecutor.Subscibe.cs @@ -14,23 +14,19 @@ namespace DotNetCore.CAP public class SubscibeQueueExecutor : IQueueExecutor { private readonly IConsumerInvokerFactory _consumerInvokerFactory; - private readonly IConsumerClientFactory _consumerClientFactory; private readonly IStateChanger _stateChanger; private readonly ILogger _logger; private readonly MethodMatcherCache _selector; - //private readonly CapOptions _options; public SubscibeQueueExecutor( IStateChanger stateChanger, MethodMatcherCache selector, IConsumerInvokerFactory consumerInvokerFactory, - IConsumerClientFactory consumerClientFactory, ILogger logger) { _selector = selector; _consumerInvokerFactory = consumerInvokerFactory; - _consumerClientFactory = consumerClientFactory; _stateChanger = stateChanger; _logger = logger; } @@ -53,7 +49,7 @@ namespace DotNetCore.CAP var newState = default(IState); if (!result.Succeeded) { - var shouldRetry = await UpdateJobForRetryAsync(message, connection); + var shouldRetry = await UpdateMessageForRetryAsync(message, connection); if (shouldRetry) { newState = new ScheduledState(); @@ -123,7 +119,7 @@ namespace DotNetCore.CAP } } - private async Task UpdateJobForRetryAsync(CapReceivedMessage message, IStorageConnection connection) + private async Task UpdateMessageForRetryAsync(CapReceivedMessage message, IStorageConnection connection) { var retryBehavior = RetryBehavior.DefaultRetry; From af4b8e1a1004f865cec3c46f5265a816269e4c5a Mon Sep 17 00:00:00 2001 From: yangxiaodong Date: Tue, 18 Jul 2017 14:26:19 +0800 Subject: [PATCH 51/68] add unit test. --- .../QueueExecutorFactoryTest.cs | 48 +++++++++++++++ .../SubscribeFinderTest.cs | 59 +++++++++++++++++++ 2 files changed, 107 insertions(+) create mode 100644 test/DotNetCore.CAP.Test/QueueExecutorFactoryTest.cs create mode 100644 test/DotNetCore.CAP.Test/SubscribeFinderTest.cs diff --git a/test/DotNetCore.CAP.Test/QueueExecutorFactoryTest.cs b/test/DotNetCore.CAP.Test/QueueExecutorFactoryTest.cs new file mode 100644 index 0000000..f1bf1e3 --- /dev/null +++ b/test/DotNetCore.CAP.Test/QueueExecutorFactoryTest.cs @@ -0,0 +1,48 @@ +using System; +using System.Collections.Generic; +using System.Text; +using Microsoft.Extensions.DependencyInjection; +using Xunit; + +namespace DotNetCore.CAP.Test +{ + public class QueueExecutorFactoryTest + { + private IServiceProvider _provider; + + public QueueExecutorFactoryTest() + { + var services = new ServiceCollection(); + services.AddLogging(); + services.AddOptions(); + services.AddCap(x => { }); + _provider = services.BuildServiceProvider(); + } + + [Fact] + public void CanCreateInstance() + { + var queueExecutorFactory = _provider.GetService(); + Assert.NotNull(queueExecutorFactory); + + var publishExecutor = queueExecutorFactory.GetInstance(Models.MessageType.Publish); + Assert.Null(publishExecutor); + + var disPatchExector = queueExecutorFactory.GetInstance(Models.MessageType.Subscribe); + Assert.NotNull(disPatchExector); + } + + [Fact] + public void CanGetSubscribeExector() + { + var queueExecutorFactory = _provider.GetService(); + Assert.NotNull(queueExecutorFactory); + + var publishExecutor = queueExecutorFactory.GetInstance(Models.MessageType.Publish); + Assert.Equal(null, publishExecutor); + } + + + + } +} diff --git a/test/DotNetCore.CAP.Test/SubscribeFinderTest.cs b/test/DotNetCore.CAP.Test/SubscribeFinderTest.cs new file mode 100644 index 0000000..54e2052 --- /dev/null +++ b/test/DotNetCore.CAP.Test/SubscribeFinderTest.cs @@ -0,0 +1,59 @@ +using System; +using System.Collections.Generic; +using System.Text; +using DotNetCore.CAP.Abstractions; +using Microsoft.Extensions.DependencyInjection; +using Xunit; + +namespace DotNetCore.CAP.Test +{ + public class SubscribeFinderTest + { + private IServiceProvider _provider; + + public SubscribeFinderTest() + { + var services = new ServiceCollection(); + services.AddScoped(); + services.AddCap(x => { }); + _provider = services.BuildServiceProvider(); + } + + [Fact] + public void CanFindControllers() + { + + } + + [Fact] + public void CanFindSubscribeService() + { + var testService = _provider.GetService(); + Assert.NotNull(testService); + Assert.IsType(testService); + } + } + + public class HomeController + { + + } + + public interface ITestService { } + + public class TestService : ITestService, ICapSubscribe + { + [CapSubscribe("test")] + public void Index() + { + + } + } + + public class CapSubscribeAttribute : TopicAttribute + { + public CapSubscribeAttribute(string name) : base(name) + { + } + } +} From 0b71a2f90ecda667c5e39fab2d9694cb181af3f7 Mon Sep 17 00:00:00 2001 From: yangxiaodong Date: Tue, 18 Jul 2017 14:26:25 +0800 Subject: [PATCH 52/68] refactor. --- src/DotNetCore.CAP.Kafka/KafkaConsumerClient.cs | 1 - src/DotNetCore.CAP.RabbitMQ/RabbitMQConsumerClient.cs | 1 - src/DotNetCore.CAP/QueueExecutorFactory.cs | 1 - 3 files changed, 3 deletions(-) diff --git a/src/DotNetCore.CAP.Kafka/KafkaConsumerClient.cs b/src/DotNetCore.CAP.Kafka/KafkaConsumerClient.cs index 014c9bd..1993d80 100644 --- a/src/DotNetCore.CAP.Kafka/KafkaConsumerClient.cs +++ b/src/DotNetCore.CAP.Kafka/KafkaConsumerClient.cs @@ -3,7 +3,6 @@ using System.Text; using System.Threading; using Confluent.Kafka; using Confluent.Kafka.Serialization; -using DotNetCore.CAP.Infrastructure; namespace DotNetCore.CAP.Kafka { diff --git a/src/DotNetCore.CAP.RabbitMQ/RabbitMQConsumerClient.cs b/src/DotNetCore.CAP.RabbitMQ/RabbitMQConsumerClient.cs index 26b0bf6..4dd2883 100644 --- a/src/DotNetCore.CAP.RabbitMQ/RabbitMQConsumerClient.cs +++ b/src/DotNetCore.CAP.RabbitMQ/RabbitMQConsumerClient.cs @@ -2,7 +2,6 @@ using System.Text; using System.Threading; using System.Threading.Tasks; -using DotNetCore.CAP.Infrastructure; using RabbitMQ.Client; using RabbitMQ.Client.Events; diff --git a/src/DotNetCore.CAP/QueueExecutorFactory.cs b/src/DotNetCore.CAP/QueueExecutorFactory.cs index 3e84684..d76f09f 100644 --- a/src/DotNetCore.CAP/QueueExecutorFactory.cs +++ b/src/DotNetCore.CAP/QueueExecutorFactory.cs @@ -1,6 +1,5 @@ using System; using System.Linq; -using System.Reflection; using DotNetCore.CAP.Models; using Microsoft.Extensions.DependencyInjection; From 9a80df47b3db30ae844fb92110e2aac3c2facfde Mon Sep 17 00:00:00 2001 From: yangxiaodong Date: Tue, 18 Jul 2017 16:53:28 +0800 Subject: [PATCH 53/68] add unit tests of sqlserver project. --- .../ConnectionUtil.cs | 2 +- .../DatabaseTestHost.cs | 14 ++ .../SqlServerStorageConnectionTest.cs | 134 ++++++++++++++++++ .../SqlServerStorageTest.cs | 70 +++++++++ .../DotNetCore.CAP.SqlServer.Test/TestHost.cs | 7 +- 5 files changed, 223 insertions(+), 4 deletions(-) create mode 100644 test/DotNetCore.CAP.SqlServer.Test/SqlServerStorageConnectionTest.cs create mode 100644 test/DotNetCore.CAP.SqlServer.Test/SqlServerStorageTest.cs diff --git a/test/DotNetCore.CAP.SqlServer.Test/ConnectionUtil.cs b/test/DotNetCore.CAP.SqlServer.Test/ConnectionUtil.cs index c9ba0b5..93e45d1 100644 --- a/test/DotNetCore.CAP.SqlServer.Test/ConnectionUtil.cs +++ b/test/DotNetCore.CAP.SqlServer.Test/ConnectionUtil.cs @@ -9,7 +9,7 @@ namespace DotNetCore.CAP.SqlServer.Test private const string ConnectionStringTemplateVariable = "Cap_SqlServer_ConnectionStringTemplate"; private const string MasterDatabaseName = "master"; - private const string DefaultDatabaseName = @"DotNetCore.CAP.EntityFrameworkCore.Test"; + private const string DefaultDatabaseName = @"DotNetCore.CAP.SqlServer.Test"; private const string DefaultConnectionStringTemplate = @"Server=192.168.2.206;Initial Catalog={0};User Id=sa;Password=123123;MultipleActiveResultSets=True"; diff --git a/test/DotNetCore.CAP.SqlServer.Test/DatabaseTestHost.cs b/test/DotNetCore.CAP.SqlServer.Test/DatabaseTestHost.cs index 380a55b..774ff40 100644 --- a/test/DotNetCore.CAP.SqlServer.Test/DatabaseTestHost.cs +++ b/test/DotNetCore.CAP.SqlServer.Test/DatabaseTestHost.cs @@ -1,4 +1,5 @@ using System.Data; +using System.Data.SqlClient; using System.Threading; using Dapper; using Microsoft.EntityFrameworkCore; @@ -29,12 +30,25 @@ namespace DotNetCore.CAP.SqlServer.Test { var storage = GetService(); var token = new CancellationTokenSource().Token; + CreateDatabase(); storage.InitializeAsync(token).Wait(); _sqlObjectInstalled = true; } } } + private void CreateDatabase() + { + var masterConn = ConnectionUtil.GetMasterConnectionString(); + var databaseName = ConnectionUtil.GetDatabaseName(); + using (var connection = ConnectionUtil.CreateConnection(masterConn)) + { + connection.Execute($@" +IF NOT EXISTS (SELECT * FROM sysdatabases WHERE name = N'{databaseName}') +CREATE DATABASE [{databaseName}];"); + } + } + private void DeleteAllData() { using (CreateScope()) diff --git a/test/DotNetCore.CAP.SqlServer.Test/SqlServerStorageConnectionTest.cs b/test/DotNetCore.CAP.SqlServer.Test/SqlServerStorageConnectionTest.cs new file mode 100644 index 0000000..dcd3793 --- /dev/null +++ b/test/DotNetCore.CAP.SqlServer.Test/SqlServerStorageConnectionTest.cs @@ -0,0 +1,134 @@ +using System; +using System.Collections.Generic; +using System.Text; +using Dapper; +using DotNetCore.CAP.Infrastructure; +using DotNetCore.CAP.Models; +using Xunit; + +namespace DotNetCore.CAP.SqlServer.Test +{ + public class SqlServerStorageConnectionTest : DatabaseTestHost + { + private SqlServerStorageConnection _storage; + + public SqlServerStorageConnectionTest() + { + var options = GetService(); + _storage = new SqlServerStorageConnection(options); + } + + [Fact] + public async void GetPublishedMessageAsync_Test() + { + var sql = "INSERT INTO [Cap].[Published]([Name],[Content],[Retries],[Added],[ExpiresAt],[StatusName]) OUTPUT INSERTED.Id VALUES(@Name,@Content,@Retries,@Added,@ExpiresAt,@StatusName);"; + var publishMessage = new CapPublishedMessage + { + Name = "SqlServerStorageConnectionTest", + Content = "", + StatusName = StatusName.Scheduled + }; + var insertedId = default(int); + using (var connection = ConnectionUtil.CreateConnection()) + { + insertedId = connection.QueryFirst(sql, publishMessage); + } + var message = await _storage.GetPublishedMessageAsync(insertedId); + Assert.NotNull(message); + Assert.Equal("SqlServerStorageConnectionTest", message.Name); + Assert.Equal(StatusName.Scheduled, message.StatusName); + } + + [Fact] + public async void FetchNextMessageAsync_Test() + { + var sql = "INSERT INTO [Cap].[Queue]([MessageId],[MessageType]) VALUES(@MessageId,@MessageType);"; + var queue = new CapQueue + { + MessageId = 3333, + MessageType = MessageType.Publish + }; + using (var connection = ConnectionUtil.CreateConnection()) + { + connection.Execute(sql, queue); + } + var fetchedMessage = await _storage.FetchNextMessageAsync(); + fetchedMessage.Dispose(); + Assert.NotNull(fetchedMessage); + Assert.Equal(MessageType.Publish, fetchedMessage.MessageType); + Assert.Equal(3333, fetchedMessage.MessageId); + } + + [Fact] + public async void StoreReceivedMessageAsync_Test() + { + var receivedMessage = new CapReceivedMessage + { + Name = "SqlServerStorageConnectionTest", + Content = "", + Group = "mygroup", + StatusName = StatusName.Scheduled + }; + + Exception exception = null; + try + { + await _storage.StoreReceivedMessageAsync(receivedMessage); + } + catch (Exception ex) + { + exception = ex; + } + Assert.Null(exception); + } + + [Fact] + public async void GetReceivedMessageAsync_Test() + { + + var sql = $@" +INSERT INTO [Cap].[Received]([Name],[Group],[Content],[Retries],[Added],[ExpiresAt],[StatusName]) OUTPUT INSERTED.Id +VALUES(@Name,@Group,@Content,@Retries,@Added,@ExpiresAt,@StatusName);"; + var receivedMessage = new CapReceivedMessage + { + Name = "SqlServerStorageConnectionTest", + Content = "", + Group = "mygroup", + StatusName = StatusName.Scheduled + }; + var insertedId = default(int); + using (var connection = ConnectionUtil.CreateConnection()) + { + insertedId = connection.QueryFirst(sql, receivedMessage); + } + + var message = await _storage.GetReceivedMessageAsync(insertedId); + + Assert.NotNull(message); + Assert.Equal(StatusName.Scheduled, message.StatusName); + Assert.Equal("SqlServerStorageConnectionTest", message.Name); + Assert.Equal("mygroup", message.Group); + } + + [Fact] + public async void GetNextReceviedMessageToBeEnqueuedAsync_Test() + { + var receivedMessage = new CapReceivedMessage + { + Name = "SqlServerStorageConnectionTest", + Content = "", + Group = "mygroup", + StatusName = StatusName.Scheduled + }; + await _storage.StoreReceivedMessageAsync(receivedMessage); + + var message = await _storage.GetNextReceviedMessageToBeEnqueuedAsync(); + + Assert.NotNull(message); + Assert.Equal(StatusName.Scheduled, message.StatusName); + Assert.Equal("SqlServerStorageConnectionTest", message.Name); + Assert.Equal("mygroup", message.Group); + } + + } +} diff --git a/test/DotNetCore.CAP.SqlServer.Test/SqlServerStorageTest.cs b/test/DotNetCore.CAP.SqlServer.Test/SqlServerStorageTest.cs new file mode 100644 index 0000000..c501da2 --- /dev/null +++ b/test/DotNetCore.CAP.SqlServer.Test/SqlServerStorageTest.cs @@ -0,0 +1,70 @@ +using Xunit; +using Dapper; + +namespace DotNetCore.CAP.SqlServer.Test +{ + public class SqlServerStorageTest : DatabaseTestHost + { + [Fact] + public void Database_IsExists() + { + var master = ConnectionUtil.GetMasterConnectionString(); + using (var connection = ConnectionUtil.CreateConnection(master)) + { + var databaseName = ConnectionUtil.GetDatabaseName(); + var sql = $@" +IF EXISTS (SELECT * FROM sysdatabases WHERE name = N'{databaseName}') +SELECT 'True' +ELSE +SELECT 'False'"; + var result = connection.QueryFirst(sql); + Assert.Equal(true, result); + } + } + + [Fact] + public void DatabaseTable_Published_IsExists() + { + using (var connection = ConnectionUtil.CreateConnection()) + { + var sql = @" +IF OBJECT_ID(N'[CAP].[Published]',N'U') IS NOT NULL +SELECT 'True' +ELSE +SELECT 'False'"; + var result = connection.QueryFirst(sql); + Assert.Equal(true, result); + } + } + + [Fact] + public void DatabaseTable_Queue_IsExists() + { + using (var connection = ConnectionUtil.CreateConnection()) + { + var sql = @" +IF OBJECT_ID(N'[CAP].[Queue]',N'U') IS NOT NULL +SELECT 'True' +ELSE +SELECT 'False'"; + var result = connection.QueryFirst(sql); + Assert.Equal(true, result); + } + } + + [Fact] + public void DatabaseTable_Received_IsExists() + { + using (var connection = ConnectionUtil.CreateConnection()) + { + var sql = @" +IF OBJECT_ID(N'[CAP].[Received]',N'U') IS NOT NULL +SELECT 'True' +ELSE +SELECT 'False'"; + var result = connection.QueryFirst(sql); + Assert.Equal(true, result); + } + } + } +} diff --git a/test/DotNetCore.CAP.SqlServer.Test/TestHost.cs b/test/DotNetCore.CAP.SqlServer.Test/TestHost.cs index 3b218fc..31cbfd1 100644 --- a/test/DotNetCore.CAP.SqlServer.Test/TestHost.cs +++ b/test/DotNetCore.CAP.SqlServer.Test/TestHost.cs @@ -7,6 +7,7 @@ namespace DotNetCore.CAP.SqlServer.Test public abstract class TestHost : IDisposable { protected IServiceCollection _services; + protected string _connectionString; private IServiceProvider _provider; private IServiceProvider _scopedProvider; @@ -27,10 +28,10 @@ namespace DotNetCore.CAP.SqlServer.Test services.AddOptions(); services.AddLogging(); - var connectionString = ConnectionUtil.GetConnectionString(); - services.AddSingleton(new SqlServerOptions { ConnectionString = connectionString }); + _connectionString = ConnectionUtil.GetConnectionString(); + services.AddSingleton(new SqlServerOptions { ConnectionString = _connectionString }); services.AddSingleton(); - services.AddDbContext(options => options.UseSqlServer(connectionString)); + services.AddDbContext(options => options.UseSqlServer(_connectionString)); _services = services; } From 3a205b0b84b96db5506f5dd92d5604744ab87902 Mon Sep 17 00:00:00 2001 From: yangxiaodong Date: Wed, 19 Jul 2017 15:46:29 +0800 Subject: [PATCH 54/68] update GetService to GetRequiredService --- src/DotNetCore.CAP/Processor/IProcessingServer.Cap.cs | 8 ++++---- 1 file changed, 4 insertions(+), 4 deletions(-) diff --git a/src/DotNetCore.CAP/Processor/IProcessingServer.Cap.cs b/src/DotNetCore.CAP/Processor/IProcessingServer.Cap.cs index 242eff7..5843382 100644 --- a/src/DotNetCore.CAP/Processor/IProcessingServer.Cap.cs +++ b/src/DotNetCore.CAP/Processor/IProcessingServer.Cap.cs @@ -110,15 +110,15 @@ namespace DotNetCore.CAP.Processor var returnedProcessors = new List(); for (int i = 0; i < processorCount; i++) { - var messageProcessors = _provider.GetService(); + var messageProcessors = _provider.GetRequiredService(); _messageDispatchers.Add(messageProcessors); } returnedProcessors.AddRange(_messageDispatchers); - returnedProcessors.Add(_provider.GetService()); - returnedProcessors.Add(_provider.GetService()); + returnedProcessors.Add(_provider.GetRequiredService()); + returnedProcessors.Add(_provider.GetRequiredService()); - returnedProcessors.Add(_provider.GetService()); + returnedProcessors.Add(_provider.GetRequiredService()); return returnedProcessors.ToArray(); } From 7a1294907e8996ffb2d75d5dd2a4b3abea7924be Mon Sep 17 00:00:00 2001 From: yangxiaodong Date: Wed, 19 Jul 2017 15:46:42 +0800 Subject: [PATCH 55/68] remove unused files. --- .../Job/ComputedJobTest.cs | 56 ------ .../Job/JobProcessingServerTest.cs | 185 ------------------ 2 files changed, 241 deletions(-) delete mode 100644 test/DotNetCore.CAP.Test/Job/ComputedJobTest.cs delete mode 100644 test/DotNetCore.CAP.Test/Job/JobProcessingServerTest.cs diff --git a/test/DotNetCore.CAP.Test/Job/ComputedJobTest.cs b/test/DotNetCore.CAP.Test/Job/ComputedJobTest.cs deleted file mode 100644 index a69e0fd..0000000 --- a/test/DotNetCore.CAP.Test/Job/ComputedJobTest.cs +++ /dev/null @@ -1,56 +0,0 @@ -//using System; -//using System.Collections.Generic; -//using System.Text; -//using DotNetCore.CAP.Processor; -//using Xunit; - -//namespace DotNetCore.CAP.Test.Job -//{ -// public class ComputedJobTest -// { -// [Fact] -// public void UpdateNext_LastRunNever_SchedulesNow() -// { -// // Arrange -// var now = new DateTime(2000, 1, 1, 8, 0, 0); -// var cronJob = new CronJob(Cron.Daily()); -// var computed = new ComputedCronJob(cronJob); - -// // Act -// computed.UpdateNext(now); - -// // Assert -// Assert.Equal(computed.Next, now); -// } - -// [Fact] -// public void UpdateNext_LastRun_BeforePrev_SchedulesNow() -// { -// // Arrange -// var now = new DateTime(2000, 1, 1, 8, 0, 0); -// var cronJob = new CronJob(Cron.Daily(), now.Subtract(TimeSpan.FromDays(2))); -// var computed = new ComputedCronJob(cronJob); - -// // Act -// computed.UpdateNext(now); - -// // Assert -// Assert.Equal(computed.Next, now); -// } - -// [Fact] -// public void UpdateNext_LastRun_AfterPrev_SchedulesNormal() -// { -// // Arrange -// var now = new DateTime(2000, 1, 1, 8, 0, 0); -// var cronJob = new CronJob(Cron.Daily(), now.Subtract(TimeSpan.FromSeconds(5))); -// var computed = new ComputedCronJob(cronJob); - -// // Act -// computed.UpdateNext(now); - -// // Assert -// Assert.True(computed.Next > now); -// } -// } -//} \ No newline at end of file diff --git a/test/DotNetCore.CAP.Test/Job/JobProcessingServerTest.cs b/test/DotNetCore.CAP.Test/Job/JobProcessingServerTest.cs deleted file mode 100644 index cfc498d..0000000 --- a/test/DotNetCore.CAP.Test/Job/JobProcessingServerTest.cs +++ /dev/null @@ -1,185 +0,0 @@ -//using System; -//using System.Collections.Generic; -//using System.Text; -//using System.Threading; -//using System.Threading.Tasks; -//using DotNetCore.CAP.Infrastructure; -//using DotNetCore.CAP.Processor; -//using Microsoft.Extensions.DependencyInjection; -//using Moq; -//using Xunit; - -//namespace DotNetCore.CAP.Test.Job -//{ -// public class JobProcessingServerTest -// { -// private CancellationTokenSource _cancellationTokenSource; -// private ProcessingContext _context; -// private CapOptions _options; -// private IServiceProvider _provider; -// private Mock _mockStorage; - -// public JobProcessingServerTest() -// { -// _options = new CapOptions() -// { -// PollingDelay = 0 -// }; -// _mockStorage = new Mock(); -// _cancellationTokenSource = new CancellationTokenSource(); - -// var services = new ServiceCollection(); -// services.AddTransient(); -// // services.AddTransient(); -// services.AddLogging(); -// services.AddSingleton(_options); -// services.AddSingleton(_mockStorage.Object); -// _provider = services.BuildServiceProvider(); - -// _context = new ProcessingContext(_provider, _cancellationTokenSource.Token); -// } - -// //[Fact] -// //public async Task ProcessAsync_CancellationTokenCancelled_ThrowsImmediately() -// //{ -// // // Arrange -// // _cancellationTokenSource.Cancel(); -// // var fixture = Create(); - -// // // Act -// // await Assert.ThrowsAsync(() => fixture.s(_context)); -// //} - -// //[Fact] -// //public async Task ProcessAsync() -// //{ -// // // Arrange -// // var job = new CronJob( -// // InvocationData.Serialize( -// // MethodInvocation.FromExpression(() => Method())).Serialize()); - -// // var mockFetchedJob = Mock.Get(Mock.Of(fj => fj.JobId == 42)); - -// // _mockStorageConnection -// // .Setup(m => m.FetchNextJobAsync()) -// // .ReturnsAsync(mockFetchedJob.Object).Verifiable(); - -// // _mockStorageConnection -// // .Setup(m => m.GetJobAsync(42)) -// // .ReturnsAsync(job).Verifiable(); - -// // var fixture = Create(); - -// // // Act -// // fixture.Start(); - -// // // Assert -// // _mockStorageConnection.VerifyAll(); -// // _mockStateChanger.Verify(m => m.ChangeState(job, It.IsAny(), It.IsAny())); -// // mockFetchedJob.Verify(m => m.Requeue(), Times.Never); -// // mockFetchedJob.Verify(m => m.RemoveFromQueue()); -// //} - -// //[Fact] -// //public async Task ProcessAsync_Exception() -// //{ -// // // Arrange -// // var job = new Job( -// // InvocationData.Serialize( -// // MethodInvocation.FromExpression(() => Throw())).Serialize()); - -// // var mockFetchedJob = Mock.Get(Mock.Of(fj => fj.JobId == 42)); - -// // _mockStorageConnection -// // .Setup(m => m.FetchNextJobAsync()) -// // .ReturnsAsync(mockFetchedJob.Object); - -// // _mockStorageConnection -// // .Setup(m => m.GetJobAsync(42)) -// // .ReturnsAsync(job); - -// // _mockStateChanger.Setup(m => m.ChangeState(job, It.IsAny(), It.IsAny())) -// // .Throws(); - -// // var fixture = Create(); - -// // // Act -// // await fixture.ProcessAsync(_context); - -// // // Assert -// // job.Retries.Should().Be(0); -// // mockFetchedJob.Verify(m => m.Requeue()); -// //} - -// //[Fact] -// //public async Task ProcessAsync_JobThrows() -// //{ -// // // Arrange -// // var job = new Job( -// // InvocationData.Serialize( -// // MethodInvocation.FromExpression(() => Throw())).Serialize()); - -// // var mockFetchedJob = Mock.Get(Mock.Of(fj => fj.JobId == 42)); - -// // _mockStorageConnection -// // .Setup(m => m.FetchNextJobAsync()) -// // .ReturnsAsync(mockFetchedJob.Object).Verifiable(); - -// // _mockStorageConnection -// // .Setup(m => m.GetJobAsync(42)) -// // .ReturnsAsync(job).Verifiable(); - -// // var fixture = Create(); - -// // // Act -// // await fixture.ProcessAsync(_context); - -// // // Assert -// // job.Retries.Should().Be(1); -// // _mockStorageTransaction.Verify(m => m.UpdateJob(job)); -// // _mockStorageConnection.VerifyAll(); -// // _mockStateChanger.Verify(m => m.ChangeState(job, It.IsAny(), It.IsAny())); -// // mockFetchedJob.Verify(m => m.RemoveFromQueue()); -// //} - -// //[Fact] -// //public async Task ProcessAsync_JobThrows_WithNoRetry() -// //{ -// // // Arrange -// // var job = new Job( -// // InvocationData.Serialize( -// // MethodInvocation.FromExpression(j => j.Throw())).Serialize()); - -// // var mockFetchedJob = Mock.Get(Mock.Of(fj => fj.JobId == 42)); - -// // _mockStorageConnection -// // .Setup(m => m.FetchNextJobAsync()) -// // .ReturnsAsync(mockFetchedJob.Object); - -// // _mockStorageConnection -// // .Setup(m => m.GetJobAsync(42)) -// // .ReturnsAsync(job); - -// // var fixture = Create(); - -// // // Act -// // await fixture.ProcessAsync(_context); - -// // // Assert -// // _mockStateChanger.Verify(m => m.ChangeState(job, It.IsAny(), It.IsAny())); -// //} - -// private JobProcessingServer Create() -// => _provider.GetService(); - -// //public static void Method() { } - -// //public static void Throw() { throw new Exception(); } - -// //private class NoRetryJob : IRetryable -// //{ -// // public RetryBehavior RetryBehavior => new RetryBehavior(false); -// // public void Throw() { throw new Exception(); } -// //} -// } -//} \ No newline at end of file From 43f12ed9713aa9b04222ac7ff9ac49a3cb931f99 Mon Sep 17 00:00:00 2001 From: yangxiaodong Date: Wed, 19 Jul 2017 15:46:57 +0800 Subject: [PATCH 56/68] delete log message. --- src/DotNetCore.CAP/Processor/IDispatcher.Default.cs | 2 -- 1 file changed, 2 deletions(-) diff --git a/src/DotNetCore.CAP/Processor/IDispatcher.Default.cs b/src/DotNetCore.CAP/Processor/IDispatcher.Default.cs index 53a0a73..203b564 100644 --- a/src/DotNetCore.CAP/Processor/IDispatcher.Default.cs +++ b/src/DotNetCore.CAP/Processor/IDispatcher.Default.cs @@ -48,8 +48,6 @@ namespace DotNetCore.CAP.Processor { try { - _logger.LogInformation("BaseMessageJobProcessor processing ..."); - var worked = await Step(context); context.ThrowIfStopping(); From 4e9249b1cf618d52038ec987a031b059bb9b3292 Mon Sep 17 00:00:00 2001 From: yangxiaodong Date: Wed, 19 Jul 2017 15:47:24 +0800 Subject: [PATCH 57/68] relocation. --- test/DotNetCore.CAP.Test/{ => Processor}/StateChangerTest.cs | 0 1 file changed, 0 insertions(+), 0 deletions(-) rename test/DotNetCore.CAP.Test/{ => Processor}/StateChangerTest.cs (100%) diff --git a/test/DotNetCore.CAP.Test/StateChangerTest.cs b/test/DotNetCore.CAP.Test/Processor/StateChangerTest.cs similarity index 100% rename from test/DotNetCore.CAP.Test/StateChangerTest.cs rename to test/DotNetCore.CAP.Test/Processor/StateChangerTest.cs From 0f573d5ef79aa84127a070e4c5bfd71bd27ace1c Mon Sep 17 00:00:00 2001 From: yangxiaodong Date: Wed, 19 Jul 2017 15:47:42 +0800 Subject: [PATCH 58/68] add unit tests of Dispatcher. --- .../Processor/DefaultDispatcherTest.cs | 93 +++++++++++++++++++ 1 file changed, 93 insertions(+) create mode 100644 test/DotNetCore.CAP.Test/Processor/DefaultDispatcherTest.cs diff --git a/test/DotNetCore.CAP.Test/Processor/DefaultDispatcherTest.cs b/test/DotNetCore.CAP.Test/Processor/DefaultDispatcherTest.cs new file mode 100644 index 0000000..7ff1d19 --- /dev/null +++ b/test/DotNetCore.CAP.Test/Processor/DefaultDispatcherTest.cs @@ -0,0 +1,93 @@ +using System; +using System.Collections.Generic; +using System.Text; +using System.Threading; +using System.Threading.Tasks; +using DotNetCore.CAP.Infrastructure; +using DotNetCore.CAP.Models; +using DotNetCore.CAP.Processor; +using DotNetCore.CAP.Processor.States; +using Microsoft.Extensions.DependencyInjection; +using Microsoft.Extensions.Options; +using Moq; +using Xunit; + +namespace DotNetCore.CAP.Test +{ + public class DefaultDispatcherTest + { + private CancellationTokenSource _cancellationTokenSource; + private ProcessingContext _context; + private IServiceProvider _provider; + private Mock _mockStorageConnection; + private Mock _mockQueueExecutorFactory; + private Mock _mockQueueExecutor; + + public DefaultDispatcherTest() + { + _mockStorageConnection = new Mock(); + _mockQueueExecutorFactory = new Mock(); + _mockQueueExecutor = new Mock(); + _mockQueueExecutorFactory.Setup(x => x.GetInstance(MessageType.Publish)).Returns(_mockQueueExecutor.Object); + _cancellationTokenSource = new CancellationTokenSource(); + + var services = new ServiceCollection(); + services.AddTransient(); + services.AddLogging(); + services.Configure>(x => { }); + services.AddOptions(); + services.AddSingleton(_mockStorageConnection.Object); + services.AddSingleton(_mockQueueExecutorFactory.Object); + _provider = services.BuildServiceProvider(); + + _context = new ProcessingContext(_provider, _cancellationTokenSource.Token); + } + + [Fact] + public void MockTest() + { + Assert.NotNull(_provider.GetServices()); + } + + [Fact] + public async void ProcessAsync_CancellationTokenCancelled_ThrowsImmediately() + { + // Arrange + _cancellationTokenSource.Cancel(); + var fixture = Create(); + + // Act + await Assert.ThrowsAsync(() => fixture.ProcessAsync(_context)); + } + + [Fact] + public async Task ProcessAsync() + { + // Arrange + var job = new CapPublishedMessage { + + }; + + var mockFetchedJob = Mock.Get(Mock.Of(fj => fj.MessageId == 42 && fj.MessageType == MessageType.Publish )); + + _mockStorageConnection + .Setup(m => m.FetchNextMessageAsync()) + .ReturnsAsync(mockFetchedJob.Object).Verifiable(); + + _mockQueueExecutor + .Setup(x => x.ExecuteAsync(_mockStorageConnection.Object, mockFetchedJob.Object)) + .Returns(Task.FromResult(OperateResult.Success)); + + var fixture = Create(); + + // Act + await fixture.ProcessAsync(_context); + + // Assert + _mockStorageConnection.VerifyAll(); + } + + private DefaultDispatcher Create() + => _provider.GetService(); + } +} \ No newline at end of file From e7fe6e7fa7f8a5b104358430040334bcafc5df27 Mon Sep 17 00:00:00 2001 From: yangxiaodong Date: Wed, 19 Jul 2017 16:11:58 +0800 Subject: [PATCH 59/68] update guide with new api. --- README.zh-cn.md | 41 +++++++++++++++++++++++++++++++++++------ 1 file changed, 35 insertions(+), 6 deletions(-) diff --git a/README.zh-cn.md b/README.zh-cn.md index f04265d..bbb356b 100644 --- a/README.zh-cn.md +++ b/README.zh-cn.md @@ -6,6 +6,7 @@ [![Travis branch](https://img.shields.io/travis/dotnetcore/CAP/master.svg?label=travis-ci)](https://travis-ci.org/dotnetcore/CAP) [![AppVeyor](https://ci.appveyor.com/api/projects/status/4mpe0tbu7n126vyw?svg=true)](https://ci.appveyor.com/project/yuleyule66/cap) [![NuGet](https://img.shields.io/nuget/vpre/DotNetCore.CAP.svg)](https://www.nuget.org/packages/DotNetCore.CAP/) +[![Member Project Of .NET China Foundation](https://github.com/dotnetcore/Home/raw/master/icons/member-project-of-netchina.png)](https://github.com/dotnetcore) [![GitHub license](https://img.shields.io/badge/license-MIT-blue.svg)](https://raw.githubusercontent.com/dotnetcore/CAP/master/LICENSE.txt) CAP 是一个在分布式系统(SOA、MicroService)中实现最终一致性的库,它具有轻量级、易使用、高性能等特点。 @@ -30,6 +31,10 @@ CAP 具有消息持久化的功能,当你的服务进行重启或者宕机时 你可以运行以下下命令在你的项目中安装 CAP。 +``` +PM> Install-Package DotNetCore.CAP -Pre +``` + 如果你的消息队列使用的是 Kafka 的话,你可以: ``` @@ -42,10 +47,10 @@ PM> Install-Package DotNetCore.CAP.Kafka -Pre PM> Install-Package DotNetCore.CAP.RabbitMQ -Pre ``` -CAP 默认提供了 Entity Framwork 作为数据库存储: +CAP 默认提供了 Sql Server 的扩展作为数据库存储(MySql的正在开发中): ``` -PM> Install-Package DotNetCore.CAP.EntityFrameworkCore -Pre +PM> Install-Package DotNetCore.CAP.SqlServer -Pre ``` ### Configuration @@ -57,11 +62,23 @@ public void ConfigureServices(IServiceCollection services) { ...... - services.AddDbContext(); + services.AddDbContext(); - services.AddCap() - .AddEntityFrameworkStores() - .AddKafka(x => x.Servers = "localhost:9092"); + services.AddCap(x => + { + // 如果你的 SqlServer 使用的 EF 进行数据操作,你需要添加如下配置: + // 注意: 你不需要再次配置 x.UseSqlServer(""") + x.UseEntityFramework(); + + // 如果你使用的Dapper,你需要添加如下配置: + x.UseSqlServer("数据库连接字符串"); + + // 如果你使用的 RabbitMQ 作为MQ,你需要添加如下配置: + x.UseRabbitMQ("localhost"); + + //如果你使用的 Kafka 作为MQ,你需要添加如下配置: + x.UseKafka("localhost"); + }); } public void Configure(IApplicationBuilder app) @@ -96,6 +113,18 @@ public class PublishController : Controller return Ok(); } + + [Route("~/checkAccountWithTrans")] + public async Task PublishMessageWithTransaction([FromServices]AppDbContext dbContext) + { + using (var trans = dbContext.Database.BeginTransaction()) + { + await _publisher.PublishAsync("xxx.services.account.check", new Person { Name = "Foo", Age = 11 }); + + trans.Commit(); + } + return Ok(); + } } ``` From c454670ab6f23526e0791df8b2d643371e88a874 Mon Sep 17 00:00:00 2001 From: yangxiaodong Date: Wed, 19 Jul 2017 16:58:50 +0800 Subject: [PATCH 60/68] release 0.1.1 --- .gitignore | 1 + appveyor.yml | 4 ++-- build/version.props | 2 +- 3 files changed, 4 insertions(+), 3 deletions(-) diff --git a/.gitignore b/.gitignore index 3ad5fdf..9960815 100644 --- a/.gitignore +++ b/.gitignore @@ -32,3 +32,4 @@ obj/ bin/ /.idea/.idea.CAP /.idea/.idea.CAP +/.idea diff --git a/appveyor.yml b/appveyor.yml index ecd2784..5f1bfc8 100644 --- a/appveyor.yml +++ b/appveyor.yml @@ -15,8 +15,8 @@ artifacts: deploy: provider: NuGet on: - appveyor_repo_tag: true + appveyor_repo_tag: false api_key: - secure: P4da9c6a6-00e1-47d0-a821-b62380362dc9 + secure: U62rpGTEqztrUO4ncscm4XSaAoCSmWwT/rOWO/2JJS44psJvl0QpjRL0o0ughMoY skip_symbols: true artifact: /artifacts\/packages\/.+\.nupkg/ diff --git a/build/version.props b/build/version.props index 3e9fc0c..c1235f0 100644 --- a/build/version.props +++ b/build/version.props @@ -2,7 +2,7 @@ 0 1 - 0 + 1 $(VersionMajor).$(VersionMinor).$(VersionPatch) From e11e34cfe40a6179d97edd4467ff734840bed3d9 Mon Sep 17 00:00:00 2001 From: yangxiaodong Date: Wed, 19 Jul 2017 17:33:56 +0800 Subject: [PATCH 61/68] switch to sql server 2014 --- appveyor.yml | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/appveyor.yml b/appveyor.yml index 5f1bfc8..8a48a43 100644 --- a/appveyor.yml +++ b/appveyor.yml @@ -3,9 +3,9 @@ os: Visual Studio 2015 environment: BUILDING_ON_PLATFORM: win BuildEnvironment: appveyor - Cap_SqlServer_ConnectionStringTemplate: Server=.\SQL2012SP1;Database={0};User ID=sa;Password=Password12! + Cap_SqlServer_ConnectionStringTemplate: Server=(local)\SQL2014;Database={0};User ID=sa;Password=Password12! services: - - mssql2012sp1 + - mssql2014 build_script: - ps: ./ConfigureMSDTC.ps1 - ps: ./build.ps1 From 7512c116334a333efc9712db4ba428ad37944b87 Mon Sep 17 00:00:00 2001 From: yangxiaodong Date: Wed, 19 Jul 2017 17:57:43 +0800 Subject: [PATCH 62/68] Add concurrent locks prevent multithreaded execution create the database --- .../DatabaseTestHost.cs | 27 +-- .../EFMessageStoreTest.cs | 168 ------------------ 2 files changed, 15 insertions(+), 180 deletions(-) delete mode 100644 test/DotNetCore.CAP.SqlServer.Test/EFMessageStoreTest.cs diff --git a/test/DotNetCore.CAP.SqlServer.Test/DatabaseTestHost.cs b/test/DotNetCore.CAP.SqlServer.Test/DatabaseTestHost.cs index 774ff40..b32fd74 100644 --- a/test/DotNetCore.CAP.SqlServer.Test/DatabaseTestHost.cs +++ b/test/DotNetCore.CAP.SqlServer.Test/DatabaseTestHost.cs @@ -1,5 +1,4 @@ using System.Data; -using System.Data.SqlClient; using System.Threading; using Dapper; using Microsoft.EntityFrameworkCore; @@ -9,11 +8,18 @@ namespace DotNetCore.CAP.SqlServer.Test public abstract class DatabaseTestHost : TestHost { private static bool _sqlObjectInstalled; + public static object _lock = new object(); protected override void PostBuildServices() { base.PostBuildServices(); - InitializeDatabase(); + lock (_lock) + { + if (!_sqlObjectInstalled) + { + InitializeDatabase(); + } + } } public override void Dispose() @@ -24,16 +30,13 @@ namespace DotNetCore.CAP.SqlServer.Test private void InitializeDatabase() { - if (!_sqlObjectInstalled) + using (CreateScope()) { - using (CreateScope()) - { - var storage = GetService(); - var token = new CancellationTokenSource().Token; - CreateDatabase(); - storage.InitializeAsync(token).Wait(); - _sqlObjectInstalled = true; - } + var storage = GetService(); + var token = new CancellationTokenSource().Token; + CreateDatabase(); + storage.InitializeAsync(token).Wait(); + _sqlObjectInstalled = true; } } @@ -44,7 +47,7 @@ namespace DotNetCore.CAP.SqlServer.Test using (var connection = ConnectionUtil.CreateConnection(masterConn)) { connection.Execute($@" -IF NOT EXISTS (SELECT * FROM sysdatabases WHERE name = N'{databaseName}') +IF NOT EXISTS (SELECT * FROM sysdatabases WHERE name = N'{databaseName}') CREATE DATABASE [{databaseName}];"); } } diff --git a/test/DotNetCore.CAP.SqlServer.Test/EFMessageStoreTest.cs b/test/DotNetCore.CAP.SqlServer.Test/EFMessageStoreTest.cs deleted file mode 100644 index e59f393..0000000 --- a/test/DotNetCore.CAP.SqlServer.Test/EFMessageStoreTest.cs +++ /dev/null @@ -1,168 +0,0 @@ -namespace DotNetCore.CAP.EntityFrameworkCore.Test -{ - //public class EFMessageStoreTest : DatabaseTestHost - //{ - // [Fact] - // public void CanCreateSentMessageUsingEF() - // { - // using (var db = CreateContext()) - // { - // var guid = Guid.NewGuid().ToString(); - // var message = new CapPublishedMessage - // { - // Id = guid, - // Content = "this is message body", - // StatusName = StatusName.Enqueued - // }; - // db.Attach(message).State = Microsoft.EntityFrameworkCore.EntityState.Added; - - // db.SaveChanges(); - - // Assert.True(db.CapSentMessages.Any(u => u.Id == guid)); - // Assert.NotNull(db.CapSentMessages.FirstOrDefault(u => u.StatusName == StatusName.Enqueued)); - // } - // } - - // [Fact] - // public void CanUpdateSentMessageUsingEF() - // { - // using (var db = CreateContext()) - // { - // var guid = Guid.NewGuid().ToString(); - // var message = new CapPublishedMessage - // { - // Id = guid, - // Content = "this is message body", - // StatusName = StatusName.Enqueued - // }; - // db.Attach(message).State = Microsoft.EntityFrameworkCore.EntityState.Added; - - // db.SaveChanges(); - - // var selectedMessage = db.CapSentMessages.FirstOrDefault(u => u.StatusName == StatusName.Enqueued); - // Assert.NotNull(selectedMessage); - - // selectedMessage.StatusName = StatusName.Succeeded; - // selectedMessage.Content = "Test"; - // db.SaveChanges(); - - // selectedMessage = db.CapSentMessages.FirstOrDefault(u => u.StatusName == StatusName.Succeeded); - // Assert.NotNull(selectedMessage); - // Assert.True(selectedMessage.Content == "Test"); - // } - // } - - // [Fact] - // public void CanRemoveSentMessageUsingEF() - // { - // using (var db = CreateContext()) - // { - // var guid = Guid.NewGuid().ToString(); - // var message = new CapPublishedMessage - // { - // Id = guid, - // Content = "this is message body", - // StatusName = StatusName.Enqueued - // }; - // db.Attach(message).State = Microsoft.EntityFrameworkCore.EntityState.Added; - - // db.SaveChanges(); - - // var selectedMessage = db.CapSentMessages.FirstOrDefault(u => u.StatusName == StatusName.Enqueued); - // Assert.NotNull(selectedMessage); - - // db.CapSentMessages.Remove(selectedMessage); - // db.SaveChanges(); - // selectedMessage = db.CapSentMessages.FirstOrDefault(u => u.StatusName == StatusName.Enqueued); - // Assert.Null(selectedMessage); - // } - // } - - // [Fact] - // public void CanCreateReceivedMessageUsingEF() - // { - // using (var db = CreateContext()) - // { - // var guid = Guid.NewGuid().ToString(); - // var message = new CapReceivedMessage - // { - // Id = guid, - // Content = "this is message body", - // StatusName = StatusName.Enqueued - // }; - // db.Attach(message).State = Microsoft.EntityFrameworkCore.EntityState.Added; - - // db.SaveChanges(); - - // Assert.True(db.CapReceivedMessages.Any(u => u.Id == guid)); - // Assert.NotNull(db.CapReceivedMessages.FirstOrDefault(u => u.StatusName == StatusName.Enqueued)); - // } - // } - - // [Fact] - // public void CanUpdateReceivedMessageUsingEF() - // { - // using (var db = CreateContext()) - // { - // var guid = Guid.NewGuid().ToString(); - // var message = new CapReceivedMessage - // { - // Id = guid, - // Content = "this is message body", - // StatusName = StatusName.Enqueued - // }; - // db.Attach(message).State = Microsoft.EntityFrameworkCore.EntityState.Added; - - // db.SaveChanges(); - - // var selectedMessage = db.CapReceivedMessages.FirstOrDefault(u => u.StatusName == StatusName.Enqueued); - // Assert.NotNull(selectedMessage); - - // selectedMessage.StatusName = StatusName.Succeeded; - // selectedMessage.Content = "Test"; - // db.SaveChanges(); - - // selectedMessage = db.CapReceivedMessages.FirstOrDefault(u => u.StatusName == StatusName.Succeeded); - // Assert.NotNull(selectedMessage); - // Assert.True(selectedMessage.Content == "Test"); - // } - // } - - // [Fact] - // public void CanRemoveReceivedMessageUsingEF() - // { - // using (var db = CreateContext()) - // { - // var guid = Guid.NewGuid().ToString(); - // var message = new CapReceivedMessage - // { - // Id = guid, - // Content = "this is message body", - // StatusName = StatusName.Enqueued - // }; - // db.Attach(message).State = Microsoft.EntityFrameworkCore.EntityState.Added; - - // db.SaveChanges(); - - // var selectedMessage = db.CapReceivedMessages.FirstOrDefault(u => u.StatusName == StatusName.Enqueued); - // Assert.NotNull(selectedMessage); - - // db.CapReceivedMessages.Remove(selectedMessage); - // db.SaveChanges(); - // selectedMessage = db.CapReceivedMessages.FirstOrDefault(u => u.StatusName == StatusName.Enqueued); - // Assert.Null(selectedMessage); - // } - // } - - // public TestDbContext CreateContext(bool delete = false) - // { - // var db = Provider.GetRequiredService(); - // if (delete) - // { - // db.Database.EnsureDeleted(); - // } - // db.Database.EnsureCreated(); - // return db; - // } - //} -} \ No newline at end of file From 3ad72f4277ecbd3a371c18662caa6498b157aa48 Mon Sep 17 00:00:00 2001 From: yangxiaodong Date: Wed, 19 Jul 2017 18:08:18 +0800 Subject: [PATCH 63/68] update unit tests. --- .../SqlServerStorageConnectionTest.cs | 11 ++++++----- .../SqlServerStorageTest.cs | 6 +++--- 2 files changed, 9 insertions(+), 8 deletions(-) diff --git a/test/DotNetCore.CAP.SqlServer.Test/SqlServerStorageConnectionTest.cs b/test/DotNetCore.CAP.SqlServer.Test/SqlServerStorageConnectionTest.cs index dcd3793..db797d9 100644 --- a/test/DotNetCore.CAP.SqlServer.Test/SqlServerStorageConnectionTest.cs +++ b/test/DotNetCore.CAP.SqlServer.Test/SqlServerStorageConnectionTest.cs @@ -1,6 +1,7 @@ using System; using System.Collections.Generic; using System.Text; +using System.Threading.Tasks; using Dapper; using DotNetCore.CAP.Infrastructure; using DotNetCore.CAP.Models; @@ -19,7 +20,7 @@ namespace DotNetCore.CAP.SqlServer.Test } [Fact] - public async void GetPublishedMessageAsync_Test() + public async Task GetPublishedMessageAsync_Test() { var sql = "INSERT INTO [Cap].[Published]([Name],[Content],[Retries],[Added],[ExpiresAt],[StatusName]) OUTPUT INSERTED.Id VALUES(@Name,@Content,@Retries,@Added,@ExpiresAt,@StatusName);"; var publishMessage = new CapPublishedMessage @@ -40,7 +41,7 @@ namespace DotNetCore.CAP.SqlServer.Test } [Fact] - public async void FetchNextMessageAsync_Test() + public async Task FetchNextMessageAsync_Test() { var sql = "INSERT INTO [Cap].[Queue]([MessageId],[MessageType]) VALUES(@MessageId,@MessageType);"; var queue = new CapQueue @@ -60,7 +61,7 @@ namespace DotNetCore.CAP.SqlServer.Test } [Fact] - public async void StoreReceivedMessageAsync_Test() + public async Task StoreReceivedMessageAsync_Test() { var receivedMessage = new CapReceivedMessage { @@ -83,7 +84,7 @@ namespace DotNetCore.CAP.SqlServer.Test } [Fact] - public async void GetReceivedMessageAsync_Test() + public async Task GetReceivedMessageAsync_Test() { var sql = $@" @@ -111,7 +112,7 @@ VALUES(@Name,@Group,@Content,@Retries,@Added,@ExpiresAt,@StatusName);"; } [Fact] - public async void GetNextReceviedMessageToBeEnqueuedAsync_Test() + public async Task GetNextReceviedMessageToBeEnqueuedAsync_Test() { var receivedMessage = new CapReceivedMessage { diff --git a/test/DotNetCore.CAP.SqlServer.Test/SqlServerStorageTest.cs b/test/DotNetCore.CAP.SqlServer.Test/SqlServerStorageTest.cs index c501da2..5ca727b 100644 --- a/test/DotNetCore.CAP.SqlServer.Test/SqlServerStorageTest.cs +++ b/test/DotNetCore.CAP.SqlServer.Test/SqlServerStorageTest.cs @@ -28,7 +28,7 @@ SELECT 'False'"; using (var connection = ConnectionUtil.CreateConnection()) { var sql = @" -IF OBJECT_ID(N'[CAP].[Published]',N'U') IS NOT NULL +IF OBJECT_ID(N'[Cap].[Published]',N'U') IS NOT NULL SELECT 'True' ELSE SELECT 'False'"; @@ -43,7 +43,7 @@ SELECT 'False'"; using (var connection = ConnectionUtil.CreateConnection()) { var sql = @" -IF OBJECT_ID(N'[CAP].[Queue]',N'U') IS NOT NULL +IF OBJECT_ID(N'[Cap].[Queue]',N'U') IS NOT NULL SELECT 'True' ELSE SELECT 'False'"; @@ -58,7 +58,7 @@ SELECT 'False'"; using (var connection = ConnectionUtil.CreateConnection()) { var sql = @" -IF OBJECT_ID(N'[CAP].[Received]',N'U') IS NOT NULL +IF OBJECT_ID(N'[Cap].[Received]',N'U') IS NOT NULL SELECT 'True' ELSE SELECT 'False'"; From cf5708e7a541483cee1d51a37fd100e338376cfb Mon Sep 17 00:00:00 2001 From: yangxiaodong Date: Wed, 19 Jul 2017 18:28:47 +0800 Subject: [PATCH 64/68] update for test. --- .../SqlServerStorageConnectionTest.cs | 242 +++++++++--------- .../SqlServerStorageTest.cs | 88 +++---- 2 files changed, 165 insertions(+), 165 deletions(-) diff --git a/test/DotNetCore.CAP.SqlServer.Test/SqlServerStorageConnectionTest.cs b/test/DotNetCore.CAP.SqlServer.Test/SqlServerStorageConnectionTest.cs index db797d9..2ed752f 100644 --- a/test/DotNetCore.CAP.SqlServer.Test/SqlServerStorageConnectionTest.cs +++ b/test/DotNetCore.CAP.SqlServer.Test/SqlServerStorageConnectionTest.cs @@ -1,135 +1,135 @@ -using System; -using System.Collections.Generic; -using System.Text; -using System.Threading.Tasks; -using Dapper; -using DotNetCore.CAP.Infrastructure; -using DotNetCore.CAP.Models; -using Xunit; +//using System; +//using System.Collections.Generic; +//using System.Text; +//using System.Threading.Tasks; +//using Dapper; +//using DotNetCore.CAP.Infrastructure; +//using DotNetCore.CAP.Models; +//using Xunit; -namespace DotNetCore.CAP.SqlServer.Test -{ - public class SqlServerStorageConnectionTest : DatabaseTestHost - { - private SqlServerStorageConnection _storage; +//namespace DotNetCore.CAP.SqlServer.Test +//{ +// public class SqlServerStorageConnectionTest : DatabaseTestHost +// { +// private SqlServerStorageConnection _storage; - public SqlServerStorageConnectionTest() - { - var options = GetService(); - _storage = new SqlServerStorageConnection(options); - } +// public SqlServerStorageConnectionTest() +// { +// var options = GetService(); +// _storage = new SqlServerStorageConnection(options); +// } - [Fact] - public async Task GetPublishedMessageAsync_Test() - { - var sql = "INSERT INTO [Cap].[Published]([Name],[Content],[Retries],[Added],[ExpiresAt],[StatusName]) OUTPUT INSERTED.Id VALUES(@Name,@Content,@Retries,@Added,@ExpiresAt,@StatusName);"; - var publishMessage = new CapPublishedMessage - { - Name = "SqlServerStorageConnectionTest", - Content = "", - StatusName = StatusName.Scheduled - }; - var insertedId = default(int); - using (var connection = ConnectionUtil.CreateConnection()) - { - insertedId = connection.QueryFirst(sql, publishMessage); - } - var message = await _storage.GetPublishedMessageAsync(insertedId); - Assert.NotNull(message); - Assert.Equal("SqlServerStorageConnectionTest", message.Name); - Assert.Equal(StatusName.Scheduled, message.StatusName); - } +// [Fact] +// public async Task GetPublishedMessageAsync_Test() +// { +// var sql = "INSERT INTO [Cap].[Published]([Name],[Content],[Retries],[Added],[ExpiresAt],[StatusName]) OUTPUT INSERTED.Id VALUES(@Name,@Content,@Retries,@Added,@ExpiresAt,@StatusName);"; +// var publishMessage = new CapPublishedMessage +// { +// Name = "SqlServerStorageConnectionTest", +// Content = "", +// StatusName = StatusName.Scheduled +// }; +// var insertedId = default(int); +// using (var connection = ConnectionUtil.CreateConnection()) +// { +// insertedId = connection.QueryFirst(sql, publishMessage); +// } +// var message = await _storage.GetPublishedMessageAsync(insertedId); +// Assert.NotNull(message); +// Assert.Equal("SqlServerStorageConnectionTest", message.Name); +// Assert.Equal(StatusName.Scheduled, message.StatusName); +// } - [Fact] - public async Task FetchNextMessageAsync_Test() - { - var sql = "INSERT INTO [Cap].[Queue]([MessageId],[MessageType]) VALUES(@MessageId,@MessageType);"; - var queue = new CapQueue - { - MessageId = 3333, - MessageType = MessageType.Publish - }; - using (var connection = ConnectionUtil.CreateConnection()) - { - connection.Execute(sql, queue); - } - var fetchedMessage = await _storage.FetchNextMessageAsync(); - fetchedMessage.Dispose(); - Assert.NotNull(fetchedMessage); - Assert.Equal(MessageType.Publish, fetchedMessage.MessageType); - Assert.Equal(3333, fetchedMessage.MessageId); - } +// [Fact] +// public async Task FetchNextMessageAsync_Test() +// { +// var sql = "INSERT INTO [Cap].[Queue]([MessageId],[MessageType]) VALUES(@MessageId,@MessageType);"; +// var queue = new CapQueue +// { +// MessageId = 3333, +// MessageType = MessageType.Publish +// }; +// using (var connection = ConnectionUtil.CreateConnection()) +// { +// connection.Execute(sql, queue); +// } +// var fetchedMessage = await _storage.FetchNextMessageAsync(); +// fetchedMessage.Dispose(); +// Assert.NotNull(fetchedMessage); +// Assert.Equal(MessageType.Publish, fetchedMessage.MessageType); +// Assert.Equal(3333, fetchedMessage.MessageId); +// } - [Fact] - public async Task StoreReceivedMessageAsync_Test() - { - var receivedMessage = new CapReceivedMessage - { - Name = "SqlServerStorageConnectionTest", - Content = "", - Group = "mygroup", - StatusName = StatusName.Scheduled - }; +// [Fact] +// public async Task StoreReceivedMessageAsync_Test() +// { +// var receivedMessage = new CapReceivedMessage +// { +// Name = "SqlServerStorageConnectionTest", +// Content = "", +// Group = "mygroup", +// StatusName = StatusName.Scheduled +// }; - Exception exception = null; - try - { - await _storage.StoreReceivedMessageAsync(receivedMessage); - } - catch (Exception ex) - { - exception = ex; - } - Assert.Null(exception); - } +// Exception exception = null; +// try +// { +// await _storage.StoreReceivedMessageAsync(receivedMessage); +// } +// catch (Exception ex) +// { +// exception = ex; +// } +// Assert.Null(exception); +// } - [Fact] - public async Task GetReceivedMessageAsync_Test() - { +// [Fact] +// public async Task GetReceivedMessageAsync_Test() +// { - var sql = $@" -INSERT INTO [Cap].[Received]([Name],[Group],[Content],[Retries],[Added],[ExpiresAt],[StatusName]) OUTPUT INSERTED.Id -VALUES(@Name,@Group,@Content,@Retries,@Added,@ExpiresAt,@StatusName);"; - var receivedMessage = new CapReceivedMessage - { - Name = "SqlServerStorageConnectionTest", - Content = "", - Group = "mygroup", - StatusName = StatusName.Scheduled - }; - var insertedId = default(int); - using (var connection = ConnectionUtil.CreateConnection()) - { - insertedId = connection.QueryFirst(sql, receivedMessage); - } +// var sql = $@" +//INSERT INTO [Cap].[Received]([Name],[Group],[Content],[Retries],[Added],[ExpiresAt],[StatusName]) OUTPUT INSERTED.Id +//VALUES(@Name,@Group,@Content,@Retries,@Added,@ExpiresAt,@StatusName);"; +// var receivedMessage = new CapReceivedMessage +// { +// Name = "SqlServerStorageConnectionTest", +// Content = "", +// Group = "mygroup", +// StatusName = StatusName.Scheduled +// }; +// var insertedId = default(int); +// using (var connection = ConnectionUtil.CreateConnection()) +// { +// insertedId = connection.QueryFirst(sql, receivedMessage); +// } - var message = await _storage.GetReceivedMessageAsync(insertedId); +// var message = await _storage.GetReceivedMessageAsync(insertedId); - Assert.NotNull(message); - Assert.Equal(StatusName.Scheduled, message.StatusName); - Assert.Equal("SqlServerStorageConnectionTest", message.Name); - Assert.Equal("mygroup", message.Group); - } +// Assert.NotNull(message); +// Assert.Equal(StatusName.Scheduled, message.StatusName); +// Assert.Equal("SqlServerStorageConnectionTest", message.Name); +// Assert.Equal("mygroup", message.Group); +// } - [Fact] - public async Task GetNextReceviedMessageToBeEnqueuedAsync_Test() - { - var receivedMessage = new CapReceivedMessage - { - Name = "SqlServerStorageConnectionTest", - Content = "", - Group = "mygroup", - StatusName = StatusName.Scheduled - }; - await _storage.StoreReceivedMessageAsync(receivedMessage); +// [Fact] +// public async Task GetNextReceviedMessageToBeEnqueuedAsync_Test() +// { +// var receivedMessage = new CapReceivedMessage +// { +// Name = "SqlServerStorageConnectionTest", +// Content = "", +// Group = "mygroup", +// StatusName = StatusName.Scheduled +// }; +// await _storage.StoreReceivedMessageAsync(receivedMessage); - var message = await _storage.GetNextReceviedMessageToBeEnqueuedAsync(); +// var message = await _storage.GetNextReceviedMessageToBeEnqueuedAsync(); - Assert.NotNull(message); - Assert.Equal(StatusName.Scheduled, message.StatusName); - Assert.Equal("SqlServerStorageConnectionTest", message.Name); - Assert.Equal("mygroup", message.Group); - } +// Assert.NotNull(message); +// Assert.Equal(StatusName.Scheduled, message.StatusName); +// Assert.Equal("SqlServerStorageConnectionTest", message.Name); +// Assert.Equal("mygroup", message.Group); +// } - } -} +// } +//} diff --git a/test/DotNetCore.CAP.SqlServer.Test/SqlServerStorageTest.cs b/test/DotNetCore.CAP.SqlServer.Test/SqlServerStorageTest.cs index 5ca727b..86e3cdb 100644 --- a/test/DotNetCore.CAP.SqlServer.Test/SqlServerStorageTest.cs +++ b/test/DotNetCore.CAP.SqlServer.Test/SqlServerStorageTest.cs @@ -5,37 +5,37 @@ namespace DotNetCore.CAP.SqlServer.Test { public class SqlServerStorageTest : DatabaseTestHost { - [Fact] - public void Database_IsExists() - { - var master = ConnectionUtil.GetMasterConnectionString(); - using (var connection = ConnectionUtil.CreateConnection(master)) - { - var databaseName = ConnectionUtil.GetDatabaseName(); - var sql = $@" -IF EXISTS (SELECT * FROM sysdatabases WHERE name = N'{databaseName}') -SELECT 'True' -ELSE -SELECT 'False'"; - var result = connection.QueryFirst(sql); - Assert.Equal(true, result); - } - } +// [Fact] +// public void Database_IsExists() +// { +// var master = ConnectionUtil.GetMasterConnectionString(); +// using (var connection = ConnectionUtil.CreateConnection(master)) +// { +// var databaseName = ConnectionUtil.GetDatabaseName(); +// var sql = $@" +//IF EXISTS (SELECT * FROM sysdatabases WHERE name = N'{databaseName}') +//SELECT 'True' +//ELSE +//SELECT 'False'"; +// var result = connection.QueryFirst(sql); +// Assert.Equal(true, result); +// } +// } - [Fact] - public void DatabaseTable_Published_IsExists() - { - using (var connection = ConnectionUtil.CreateConnection()) - { - var sql = @" -IF OBJECT_ID(N'[Cap].[Published]',N'U') IS NOT NULL -SELECT 'True' -ELSE -SELECT 'False'"; - var result = connection.QueryFirst(sql); - Assert.Equal(true, result); - } - } +// [Fact] +// public void DatabaseTable_Published_IsExists() +// { +// using (var connection = ConnectionUtil.CreateConnection()) +// { +// var sql = @" +//IF OBJECT_ID(N'[Cap].[Published]',N'U') IS NOT NULL +//SELECT 'True' +//ELSE +//SELECT 'False'"; +// var result = connection.QueryFirst(sql); +// Assert.Equal(true, result); +// } +// } [Fact] public void DatabaseTable_Queue_IsExists() @@ -52,19 +52,19 @@ SELECT 'False'"; } } - [Fact] - public void DatabaseTable_Received_IsExists() - { - using (var connection = ConnectionUtil.CreateConnection()) - { - var sql = @" -IF OBJECT_ID(N'[Cap].[Received]',N'U') IS NOT NULL -SELECT 'True' -ELSE -SELECT 'False'"; - var result = connection.QueryFirst(sql); - Assert.Equal(true, result); - } - } +// [Fact] +// public void DatabaseTable_Received_IsExists() +// { +// using (var connection = ConnectionUtil.CreateConnection()) +// { +// var sql = @" +//IF OBJECT_ID(N'[Cap].[Received]',N'U') IS NOT NULL +//SELECT 'True' +//ELSE +//SELECT 'False'"; +// var result = connection.QueryFirst(sql); +// Assert.Equal(true, result); +// } +// } } } From 6bce650b2c7323a7a8d6af44d9abefe851c53380 Mon Sep 17 00:00:00 2001 From: yangxiaodong Date: Wed, 19 Jul 2017 18:34:14 +0800 Subject: [PATCH 65/68] tests --- appveyor.yml | 2 +- .../SqlServerStorageTest.cs | 88 +++++++++---------- 2 files changed, 45 insertions(+), 45 deletions(-) diff --git a/appveyor.yml b/appveyor.yml index 8a48a43..203f11c 100644 --- a/appveyor.yml +++ b/appveyor.yml @@ -15,7 +15,7 @@ artifacts: deploy: provider: NuGet on: - appveyor_repo_tag: false + appveyor_repo_tag: true api_key: secure: U62rpGTEqztrUO4ncscm4XSaAoCSmWwT/rOWO/2JJS44psJvl0QpjRL0o0ughMoY skip_symbols: true diff --git a/test/DotNetCore.CAP.SqlServer.Test/SqlServerStorageTest.cs b/test/DotNetCore.CAP.SqlServer.Test/SqlServerStorageTest.cs index 86e3cdb..5ca727b 100644 --- a/test/DotNetCore.CAP.SqlServer.Test/SqlServerStorageTest.cs +++ b/test/DotNetCore.CAP.SqlServer.Test/SqlServerStorageTest.cs @@ -5,37 +5,37 @@ namespace DotNetCore.CAP.SqlServer.Test { public class SqlServerStorageTest : DatabaseTestHost { -// [Fact] -// public void Database_IsExists() -// { -// var master = ConnectionUtil.GetMasterConnectionString(); -// using (var connection = ConnectionUtil.CreateConnection(master)) -// { -// var databaseName = ConnectionUtil.GetDatabaseName(); -// var sql = $@" -//IF EXISTS (SELECT * FROM sysdatabases WHERE name = N'{databaseName}') -//SELECT 'True' -//ELSE -//SELECT 'False'"; -// var result = connection.QueryFirst(sql); -// Assert.Equal(true, result); -// } -// } + [Fact] + public void Database_IsExists() + { + var master = ConnectionUtil.GetMasterConnectionString(); + using (var connection = ConnectionUtil.CreateConnection(master)) + { + var databaseName = ConnectionUtil.GetDatabaseName(); + var sql = $@" +IF EXISTS (SELECT * FROM sysdatabases WHERE name = N'{databaseName}') +SELECT 'True' +ELSE +SELECT 'False'"; + var result = connection.QueryFirst(sql); + Assert.Equal(true, result); + } + } -// [Fact] -// public void DatabaseTable_Published_IsExists() -// { -// using (var connection = ConnectionUtil.CreateConnection()) -// { -// var sql = @" -//IF OBJECT_ID(N'[Cap].[Published]',N'U') IS NOT NULL -//SELECT 'True' -//ELSE -//SELECT 'False'"; -// var result = connection.QueryFirst(sql); -// Assert.Equal(true, result); -// } -// } + [Fact] + public void DatabaseTable_Published_IsExists() + { + using (var connection = ConnectionUtil.CreateConnection()) + { + var sql = @" +IF OBJECT_ID(N'[Cap].[Published]',N'U') IS NOT NULL +SELECT 'True' +ELSE +SELECT 'False'"; + var result = connection.QueryFirst(sql); + Assert.Equal(true, result); + } + } [Fact] public void DatabaseTable_Queue_IsExists() @@ -52,19 +52,19 @@ SELECT 'False'"; } } -// [Fact] -// public void DatabaseTable_Received_IsExists() -// { -// using (var connection = ConnectionUtil.CreateConnection()) -// { -// var sql = @" -//IF OBJECT_ID(N'[Cap].[Received]',N'U') IS NOT NULL -//SELECT 'True' -//ELSE -//SELECT 'False'"; -// var result = connection.QueryFirst(sql); -// Assert.Equal(true, result); -// } -// } + [Fact] + public void DatabaseTable_Received_IsExists() + { + using (var connection = ConnectionUtil.CreateConnection()) + { + var sql = @" +IF OBJECT_ID(N'[Cap].[Received]',N'U') IS NOT NULL +SELECT 'True' +ELSE +SELECT 'False'"; + var result = connection.QueryFirst(sql); + Assert.Equal(true, result); + } + } } } From 2790cf679d05283bf441935b1e771a78bc70e9a2 Mon Sep 17 00:00:00 2001 From: yangxiaodong Date: Wed, 19 Jul 2017 18:39:24 +0800 Subject: [PATCH 66/68] update --- .../DatabaseTestHost.cs | 5 +- .../SqlServerStorageConnectionTest.cs | 244 +++++++++--------- 2 files changed, 126 insertions(+), 123 deletions(-) diff --git a/test/DotNetCore.CAP.SqlServer.Test/DatabaseTestHost.cs b/test/DotNetCore.CAP.SqlServer.Test/DatabaseTestHost.cs index b32fd74..afb7c96 100644 --- a/test/DotNetCore.CAP.SqlServer.Test/DatabaseTestHost.cs +++ b/test/DotNetCore.CAP.SqlServer.Test/DatabaseTestHost.cs @@ -17,7 +17,10 @@ namespace DotNetCore.CAP.SqlServer.Test { if (!_sqlObjectInstalled) { - InitializeDatabase(); + lock (this) + { + InitializeDatabase(); + } } } } diff --git a/test/DotNetCore.CAP.SqlServer.Test/SqlServerStorageConnectionTest.cs b/test/DotNetCore.CAP.SqlServer.Test/SqlServerStorageConnectionTest.cs index 2ed752f..167f66e 100644 --- a/test/DotNetCore.CAP.SqlServer.Test/SqlServerStorageConnectionTest.cs +++ b/test/DotNetCore.CAP.SqlServer.Test/SqlServerStorageConnectionTest.cs @@ -1,135 +1,135 @@ -//using System; -//using System.Collections.Generic; -//using System.Text; -//using System.Threading.Tasks; -//using Dapper; -//using DotNetCore.CAP.Infrastructure; -//using DotNetCore.CAP.Models; -//using Xunit; +using System; +using System.Collections.Generic; +using System.Text; +using System.Threading.Tasks; +using Dapper; +using DotNetCore.CAP.Infrastructure; +using DotNetCore.CAP.Models; +using Xunit; -//namespace DotNetCore.CAP.SqlServer.Test -//{ -// public class SqlServerStorageConnectionTest : DatabaseTestHost -// { -// private SqlServerStorageConnection _storage; +namespace DotNetCore.CAP.SqlServer.Test +{ + public class SqlServerStorageConnectionTest : DatabaseTestHost + { + private SqlServerStorageConnection _storage; + + public SqlServerStorageConnectionTest() + { + var options = GetService(); + _storage = new SqlServerStorageConnection(options); + } -// public SqlServerStorageConnectionTest() -// { -// var options = GetService(); -// _storage = new SqlServerStorageConnection(options); -// } + [Fact] + public async Task GetPublishedMessageAsync_Test() + { + var sql = "INSERT INTO [Cap].[Published]([Name],[Content],[Retries],[Added],[ExpiresAt],[StatusName]) OUTPUT INSERTED.Id VALUES(@Name,@Content,@Retries,@Added,@ExpiresAt,@StatusName);"; + var publishMessage = new CapPublishedMessage + { + Name = "SqlServerStorageConnectionTest", + Content = "", + StatusName = StatusName.Scheduled + }; + var insertedId = default(int); + using (var connection = ConnectionUtil.CreateConnection()) + { + insertedId = connection.QueryFirst(sql, publishMessage); + } + var message = await _storage.GetPublishedMessageAsync(insertedId); + Assert.NotNull(message); + Assert.Equal("SqlServerStorageConnectionTest", message.Name); + Assert.Equal(StatusName.Scheduled, message.StatusName); + } -// [Fact] -// public async Task GetPublishedMessageAsync_Test() -// { -// var sql = "INSERT INTO [Cap].[Published]([Name],[Content],[Retries],[Added],[ExpiresAt],[StatusName]) OUTPUT INSERTED.Id VALUES(@Name,@Content,@Retries,@Added,@ExpiresAt,@StatusName);"; -// var publishMessage = new CapPublishedMessage -// { -// Name = "SqlServerStorageConnectionTest", -// Content = "", -// StatusName = StatusName.Scheduled -// }; -// var insertedId = default(int); -// using (var connection = ConnectionUtil.CreateConnection()) -// { -// insertedId = connection.QueryFirst(sql, publishMessage); -// } -// var message = await _storage.GetPublishedMessageAsync(insertedId); -// Assert.NotNull(message); -// Assert.Equal("SqlServerStorageConnectionTest", message.Name); -// Assert.Equal(StatusName.Scheduled, message.StatusName); -// } + [Fact] + public async Task FetchNextMessageAsync_Test() + { + var sql = "INSERT INTO [Cap].[Queue]([MessageId],[MessageType]) VALUES(@MessageId,@MessageType);"; + var queue = new CapQueue + { + MessageId = 3333, + MessageType = MessageType.Publish + }; + using (var connection = ConnectionUtil.CreateConnection()) + { + connection.Execute(sql, queue); + } + var fetchedMessage = await _storage.FetchNextMessageAsync(); + fetchedMessage.Dispose(); + Assert.NotNull(fetchedMessage); + Assert.Equal(MessageType.Publish, fetchedMessage.MessageType); + Assert.Equal(3333, fetchedMessage.MessageId); + } -// [Fact] -// public async Task FetchNextMessageAsync_Test() -// { -// var sql = "INSERT INTO [Cap].[Queue]([MessageId],[MessageType]) VALUES(@MessageId,@MessageType);"; -// var queue = new CapQueue -// { -// MessageId = 3333, -// MessageType = MessageType.Publish -// }; -// using (var connection = ConnectionUtil.CreateConnection()) -// { -// connection.Execute(sql, queue); -// } -// var fetchedMessage = await _storage.FetchNextMessageAsync(); -// fetchedMessage.Dispose(); -// Assert.NotNull(fetchedMessage); -// Assert.Equal(MessageType.Publish, fetchedMessage.MessageType); -// Assert.Equal(3333, fetchedMessage.MessageId); -// } + [Fact] + public async Task StoreReceivedMessageAsync_Test() + { + var receivedMessage = new CapReceivedMessage + { + Name = "SqlServerStorageConnectionTest", + Content = "", + Group = "mygroup", + StatusName = StatusName.Scheduled + }; -// [Fact] -// public async Task StoreReceivedMessageAsync_Test() -// { -// var receivedMessage = new CapReceivedMessage -// { -// Name = "SqlServerStorageConnectionTest", -// Content = "", -// Group = "mygroup", -// StatusName = StatusName.Scheduled -// }; + Exception exception = null; + try + { + await _storage.StoreReceivedMessageAsync(receivedMessage); + } + catch (Exception ex) + { + exception = ex; + } + Assert.Null(exception); + } -// Exception exception = null; -// try -// { -// await _storage.StoreReceivedMessageAsync(receivedMessage); -// } -// catch (Exception ex) -// { -// exception = ex; -// } -// Assert.Null(exception); -// } + [Fact] + public async Task GetReceivedMessageAsync_Test() + { -// [Fact] -// public async Task GetReceivedMessageAsync_Test() -// { + var sql = $@" +INSERT INTO [Cap].[Received]([Name],[Group],[Content],[Retries],[Added],[ExpiresAt],[StatusName]) OUTPUT INSERTED.Id +VALUES(@Name,@Group,@Content,@Retries,@Added,@ExpiresAt,@StatusName);"; + var receivedMessage = new CapReceivedMessage + { + Name = "SqlServerStorageConnectionTest", + Content = "", + Group = "mygroup", + StatusName = StatusName.Scheduled + }; + var insertedId = default(int); + using (var connection = ConnectionUtil.CreateConnection()) + { + insertedId = connection.QueryFirst(sql, receivedMessage); + } -// var sql = $@" -//INSERT INTO [Cap].[Received]([Name],[Group],[Content],[Retries],[Added],[ExpiresAt],[StatusName]) OUTPUT INSERTED.Id -//VALUES(@Name,@Group,@Content,@Retries,@Added,@ExpiresAt,@StatusName);"; -// var receivedMessage = new CapReceivedMessage -// { -// Name = "SqlServerStorageConnectionTest", -// Content = "", -// Group = "mygroup", -// StatusName = StatusName.Scheduled -// }; -// var insertedId = default(int); -// using (var connection = ConnectionUtil.CreateConnection()) -// { -// insertedId = connection.QueryFirst(sql, receivedMessage); -// } + var message = await _storage.GetReceivedMessageAsync(insertedId); -// var message = await _storage.GetReceivedMessageAsync(insertedId); + Assert.NotNull(message); + Assert.Equal(StatusName.Scheduled, message.StatusName); + Assert.Equal("SqlServerStorageConnectionTest", message.Name); + Assert.Equal("mygroup", message.Group); + } -// Assert.NotNull(message); -// Assert.Equal(StatusName.Scheduled, message.StatusName); -// Assert.Equal("SqlServerStorageConnectionTest", message.Name); -// Assert.Equal("mygroup", message.Group); -// } + [Fact] + public async Task GetNextReceviedMessageToBeEnqueuedAsync_Test() + { + var receivedMessage = new CapReceivedMessage + { + Name = "SqlServerStorageConnectionTest", + Content = "", + Group = "mygroup", + StatusName = StatusName.Scheduled + }; + await _storage.StoreReceivedMessageAsync(receivedMessage); -// [Fact] -// public async Task GetNextReceviedMessageToBeEnqueuedAsync_Test() -// { -// var receivedMessage = new CapReceivedMessage -// { -// Name = "SqlServerStorageConnectionTest", -// Content = "", -// Group = "mygroup", -// StatusName = StatusName.Scheduled -// }; -// await _storage.StoreReceivedMessageAsync(receivedMessage); + var message = await _storage.GetNextReceviedMessageToBeEnqueuedAsync(); -// var message = await _storage.GetNextReceviedMessageToBeEnqueuedAsync(); + Assert.NotNull(message); + Assert.Equal(StatusName.Scheduled, message.StatusName); + Assert.Equal("SqlServerStorageConnectionTest", message.Name); + Assert.Equal("mygroup", message.Group); + } -// Assert.NotNull(message); -// Assert.Equal(StatusName.Scheduled, message.StatusName); -// Assert.Equal("SqlServerStorageConnectionTest", message.Name); -// Assert.Equal("mygroup", message.Group); -// } - -// } -//} + } +} From 00b6a0f6be38008e3be89f4cb91009173dbf5b74 Mon Sep 17 00:00:00 2001 From: yangxiaodong Date: Wed, 19 Jul 2017 18:42:24 +0800 Subject: [PATCH 67/68] tests --- .../DatabaseTestHost.cs | 5 +- .../SqlServerStorageConnectionTest.cs | 162 +++++++++--------- 2 files changed, 82 insertions(+), 85 deletions(-) diff --git a/test/DotNetCore.CAP.SqlServer.Test/DatabaseTestHost.cs b/test/DotNetCore.CAP.SqlServer.Test/DatabaseTestHost.cs index afb7c96..b32fd74 100644 --- a/test/DotNetCore.CAP.SqlServer.Test/DatabaseTestHost.cs +++ b/test/DotNetCore.CAP.SqlServer.Test/DatabaseTestHost.cs @@ -17,10 +17,7 @@ namespace DotNetCore.CAP.SqlServer.Test { if (!_sqlObjectInstalled) { - lock (this) - { - InitializeDatabase(); - } + InitializeDatabase(); } } } diff --git a/test/DotNetCore.CAP.SqlServer.Test/SqlServerStorageConnectionTest.cs b/test/DotNetCore.CAP.SqlServer.Test/SqlServerStorageConnectionTest.cs index 167f66e..003cd6f 100644 --- a/test/DotNetCore.CAP.SqlServer.Test/SqlServerStorageConnectionTest.cs +++ b/test/DotNetCore.CAP.SqlServer.Test/SqlServerStorageConnectionTest.cs @@ -40,96 +40,96 @@ namespace DotNetCore.CAP.SqlServer.Test Assert.Equal(StatusName.Scheduled, message.StatusName); } - [Fact] - public async Task FetchNextMessageAsync_Test() - { - var sql = "INSERT INTO [Cap].[Queue]([MessageId],[MessageType]) VALUES(@MessageId,@MessageType);"; - var queue = new CapQueue - { - MessageId = 3333, - MessageType = MessageType.Publish - }; - using (var connection = ConnectionUtil.CreateConnection()) - { - connection.Execute(sql, queue); - } - var fetchedMessage = await _storage.FetchNextMessageAsync(); - fetchedMessage.Dispose(); - Assert.NotNull(fetchedMessage); - Assert.Equal(MessageType.Publish, fetchedMessage.MessageType); - Assert.Equal(3333, fetchedMessage.MessageId); - } +// [Fact] +// public async Task FetchNextMessageAsync_Test() +// { +// var sql = "INSERT INTO [Cap].[Queue]([MessageId],[MessageType]) VALUES(@MessageId,@MessageType);"; +// var queue = new CapQueue +// { +// MessageId = 3333, +// MessageType = MessageType.Publish +// }; +// using (var connection = ConnectionUtil.CreateConnection()) +// { +// connection.Execute(sql, queue); +// } +// var fetchedMessage = await _storage.FetchNextMessageAsync(); +// fetchedMessage.Dispose(); +// Assert.NotNull(fetchedMessage); +// Assert.Equal(MessageType.Publish, fetchedMessage.MessageType); +// Assert.Equal(3333, fetchedMessage.MessageId); +// } - [Fact] - public async Task StoreReceivedMessageAsync_Test() - { - var receivedMessage = new CapReceivedMessage - { - Name = "SqlServerStorageConnectionTest", - Content = "", - Group = "mygroup", - StatusName = StatusName.Scheduled - }; +// [Fact] +// public async Task StoreReceivedMessageAsync_Test() +// { +// var receivedMessage = new CapReceivedMessage +// { +// Name = "SqlServerStorageConnectionTest", +// Content = "", +// Group = "mygroup", +// StatusName = StatusName.Scheduled +// }; - Exception exception = null; - try - { - await _storage.StoreReceivedMessageAsync(receivedMessage); - } - catch (Exception ex) - { - exception = ex; - } - Assert.Null(exception); - } +// Exception exception = null; +// try +// { +// await _storage.StoreReceivedMessageAsync(receivedMessage); +// } +// catch (Exception ex) +// { +// exception = ex; +// } +// Assert.Null(exception); +// } - [Fact] - public async Task GetReceivedMessageAsync_Test() - { +// [Fact] +// public async Task GetReceivedMessageAsync_Test() +// { - var sql = $@" -INSERT INTO [Cap].[Received]([Name],[Group],[Content],[Retries],[Added],[ExpiresAt],[StatusName]) OUTPUT INSERTED.Id -VALUES(@Name,@Group,@Content,@Retries,@Added,@ExpiresAt,@StatusName);"; - var receivedMessage = new CapReceivedMessage - { - Name = "SqlServerStorageConnectionTest", - Content = "", - Group = "mygroup", - StatusName = StatusName.Scheduled - }; - var insertedId = default(int); - using (var connection = ConnectionUtil.CreateConnection()) - { - insertedId = connection.QueryFirst(sql, receivedMessage); - } +// var sql = $@" +//INSERT INTO [Cap].[Received]([Name],[Group],[Content],[Retries],[Added],[ExpiresAt],[StatusName]) OUTPUT INSERTED.Id +//VALUES(@Name,@Group,@Content,@Retries,@Added,@ExpiresAt,@StatusName);"; +// var receivedMessage = new CapReceivedMessage +// { +// Name = "SqlServerStorageConnectionTest", +// Content = "", +// Group = "mygroup", +// StatusName = StatusName.Scheduled +// }; +// var insertedId = default(int); +// using (var connection = ConnectionUtil.CreateConnection()) +// { +// insertedId = connection.QueryFirst(sql, receivedMessage); +// } - var message = await _storage.GetReceivedMessageAsync(insertedId); +// var message = await _storage.GetReceivedMessageAsync(insertedId); - Assert.NotNull(message); - Assert.Equal(StatusName.Scheduled, message.StatusName); - Assert.Equal("SqlServerStorageConnectionTest", message.Name); - Assert.Equal("mygroup", message.Group); - } +// Assert.NotNull(message); +// Assert.Equal(StatusName.Scheduled, message.StatusName); +// Assert.Equal("SqlServerStorageConnectionTest", message.Name); +// Assert.Equal("mygroup", message.Group); +// } - [Fact] - public async Task GetNextReceviedMessageToBeEnqueuedAsync_Test() - { - var receivedMessage = new CapReceivedMessage - { - Name = "SqlServerStorageConnectionTest", - Content = "", - Group = "mygroup", - StatusName = StatusName.Scheduled - }; - await _storage.StoreReceivedMessageAsync(receivedMessage); +// [Fact] +// public async Task GetNextReceviedMessageToBeEnqueuedAsync_Test() +// { +// var receivedMessage = new CapReceivedMessage +// { +// Name = "SqlServerStorageConnectionTest", +// Content = "", +// Group = "mygroup", +// StatusName = StatusName.Scheduled +// }; +// await _storage.StoreReceivedMessageAsync(receivedMessage); - var message = await _storage.GetNextReceviedMessageToBeEnqueuedAsync(); +// var message = await _storage.GetNextReceviedMessageToBeEnqueuedAsync(); - Assert.NotNull(message); - Assert.Equal(StatusName.Scheduled, message.StatusName); - Assert.Equal("SqlServerStorageConnectionTest", message.Name); - Assert.Equal("mygroup", message.Group); - } +// Assert.NotNull(message); +// Assert.Equal(StatusName.Scheduled, message.StatusName); +// Assert.Equal("SqlServerStorageConnectionTest", message.Name); +// Assert.Equal("mygroup", message.Group); +// } } } From 6f917898f36a7396934e3615ca9adb6ae1fb5899 Mon Sep 17 00:00:00 2001 From: Savorboard Date: Wed, 19 Jul 2017 19:41:46 +0800 Subject: [PATCH 68/68] update tests. --- .../SqlServerStorageConnectionTest.cs | 169 +++++++++--------- .../SqlServerStorageTest.cs | 1 + 2 files changed, 85 insertions(+), 85 deletions(-) diff --git a/test/DotNetCore.CAP.SqlServer.Test/SqlServerStorageConnectionTest.cs b/test/DotNetCore.CAP.SqlServer.Test/SqlServerStorageConnectionTest.cs index 003cd6f..bd0bab4 100644 --- a/test/DotNetCore.CAP.SqlServer.Test/SqlServerStorageConnectionTest.cs +++ b/test/DotNetCore.CAP.SqlServer.Test/SqlServerStorageConnectionTest.cs @@ -1,6 +1,4 @@ using System; -using System.Collections.Generic; -using System.Text; using System.Threading.Tasks; using Dapper; using DotNetCore.CAP.Infrastructure; @@ -9,14 +7,15 @@ using Xunit; namespace DotNetCore.CAP.SqlServer.Test { + [Collection("sqlserver")] public class SqlServerStorageConnectionTest : DatabaseTestHost { private SqlServerStorageConnection _storage; - + public SqlServerStorageConnectionTest() { var options = GetService(); - _storage = new SqlServerStorageConnection(options); + _storage = new SqlServerStorageConnection(options); } [Fact] @@ -40,96 +39,96 @@ namespace DotNetCore.CAP.SqlServer.Test Assert.Equal(StatusName.Scheduled, message.StatusName); } -// [Fact] -// public async Task FetchNextMessageAsync_Test() -// { -// var sql = "INSERT INTO [Cap].[Queue]([MessageId],[MessageType]) VALUES(@MessageId,@MessageType);"; -// var queue = new CapQueue -// { -// MessageId = 3333, -// MessageType = MessageType.Publish -// }; -// using (var connection = ConnectionUtil.CreateConnection()) -// { -// connection.Execute(sql, queue); -// } -// var fetchedMessage = await _storage.FetchNextMessageAsync(); -// fetchedMessage.Dispose(); -// Assert.NotNull(fetchedMessage); -// Assert.Equal(MessageType.Publish, fetchedMessage.MessageType); -// Assert.Equal(3333, fetchedMessage.MessageId); -// } + [Fact] + public async Task FetchNextMessageAsync_Test() + { + var sql = "INSERT INTO [Cap].[Queue]([MessageId],[MessageType]) VALUES(@MessageId,@MessageType);"; + var queue = new CapQueue + { + MessageId = 3333, + MessageType = MessageType.Publish + }; + using (var connection = ConnectionUtil.CreateConnection()) + { + connection.Execute(sql, queue); + } + var fetchedMessage = await _storage.FetchNextMessageAsync(); + fetchedMessage.Dispose(); + Assert.NotNull(fetchedMessage); + Assert.Equal(MessageType.Publish, fetchedMessage.MessageType); + Assert.Equal(3333, fetchedMessage.MessageId); + } -// [Fact] -// public async Task StoreReceivedMessageAsync_Test() -// { -// var receivedMessage = new CapReceivedMessage -// { -// Name = "SqlServerStorageConnectionTest", -// Content = "", -// Group = "mygroup", -// StatusName = StatusName.Scheduled -// }; + [Fact] + public async Task StoreReceivedMessageAsync_Test() + { + var receivedMessage = new CapReceivedMessage + { + Name = "SqlServerStorageConnectionTest", + Content = "", + Group = "mygroup", + StatusName = StatusName.Scheduled + }; -// Exception exception = null; -// try -// { -// await _storage.StoreReceivedMessageAsync(receivedMessage); -// } -// catch (Exception ex) -// { -// exception = ex; -// } -// Assert.Null(exception); -// } + Exception exception = null; + try + { + await _storage.StoreReceivedMessageAsync(receivedMessage); + } + catch (Exception ex) + { + exception = ex; + } + Assert.Null(exception); + } -// [Fact] -// public async Task GetReceivedMessageAsync_Test() -// { + [Fact] + public async Task GetReceivedMessageAsync_Test() + { -// var sql = $@" -//INSERT INTO [Cap].[Received]([Name],[Group],[Content],[Retries],[Added],[ExpiresAt],[StatusName]) OUTPUT INSERTED.Id -//VALUES(@Name,@Group,@Content,@Retries,@Added,@ExpiresAt,@StatusName);"; -// var receivedMessage = new CapReceivedMessage -// { -// Name = "SqlServerStorageConnectionTest", -// Content = "", -// Group = "mygroup", -// StatusName = StatusName.Scheduled -// }; -// var insertedId = default(int); -// using (var connection = ConnectionUtil.CreateConnection()) -// { -// insertedId = connection.QueryFirst(sql, receivedMessage); -// } + var sql = $@" + INSERT INTO [Cap].[Received]([Name],[Group],[Content],[Retries],[Added],[ExpiresAt],[StatusName]) OUTPUT INSERTED.Id + VALUES(@Name,@Group,@Content,@Retries,@Added,@ExpiresAt,@StatusName);"; + var receivedMessage = new CapReceivedMessage + { + Name = "SqlServerStorageConnectionTest", + Content = "", + Group = "mygroup", + StatusName = StatusName.Scheduled + }; + var insertedId = default(int); + using (var connection = ConnectionUtil.CreateConnection()) + { + insertedId = connection.QueryFirst(sql, receivedMessage); + } -// var message = await _storage.GetReceivedMessageAsync(insertedId); + var message = await _storage.GetReceivedMessageAsync(insertedId); -// Assert.NotNull(message); -// Assert.Equal(StatusName.Scheduled, message.StatusName); -// Assert.Equal("SqlServerStorageConnectionTest", message.Name); -// Assert.Equal("mygroup", message.Group); -// } + Assert.NotNull(message); + Assert.Equal(StatusName.Scheduled, message.StatusName); + Assert.Equal("SqlServerStorageConnectionTest", message.Name); + Assert.Equal("mygroup", message.Group); + } -// [Fact] -// public async Task GetNextReceviedMessageToBeEnqueuedAsync_Test() -// { -// var receivedMessage = new CapReceivedMessage -// { -// Name = "SqlServerStorageConnectionTest", -// Content = "", -// Group = "mygroup", -// StatusName = StatusName.Scheduled -// }; -// await _storage.StoreReceivedMessageAsync(receivedMessage); + [Fact] + public async Task GetNextReceviedMessageToBeEnqueuedAsync_Test() + { + var receivedMessage = new CapReceivedMessage + { + Name = "SqlServerStorageConnectionTest", + Content = "", + Group = "mygroup", + StatusName = StatusName.Scheduled + }; + await _storage.StoreReceivedMessageAsync(receivedMessage); -// var message = await _storage.GetNextReceviedMessageToBeEnqueuedAsync(); + var message = await _storage.GetNextReceviedMessageToBeEnqueuedAsync(); -// Assert.NotNull(message); -// Assert.Equal(StatusName.Scheduled, message.StatusName); -// Assert.Equal("SqlServerStorageConnectionTest", message.Name); -// Assert.Equal("mygroup", message.Group); -// } + Assert.NotNull(message); + Assert.Equal(StatusName.Scheduled, message.StatusName); + Assert.Equal("SqlServerStorageConnectionTest", message.Name); + Assert.Equal("mygroup", message.Group); + } } } diff --git a/test/DotNetCore.CAP.SqlServer.Test/SqlServerStorageTest.cs b/test/DotNetCore.CAP.SqlServer.Test/SqlServerStorageTest.cs index 5ca727b..38fb6c1 100644 --- a/test/DotNetCore.CAP.SqlServer.Test/SqlServerStorageTest.cs +++ b/test/DotNetCore.CAP.SqlServer.Test/SqlServerStorageTest.cs @@ -3,6 +3,7 @@ using Dapper; namespace DotNetCore.CAP.SqlServer.Test { + [Collection("sqlserver")] public class SqlServerStorageTest : DatabaseTestHost { [Fact]