Commit aa597fca authored by yangxiaodong's avatar yangxiaodong

Migration project to DotNetCore group, modify the namespace and assembly name.

parent e56637f5
This source diff could not be displayed because it is too large. You can view the blob instead.
 
Microsoft Visual Studio Solution File, Format Version 12.00 Microsoft Visual Studio Solution File, Format Version 12.00
# Visual Studio 15 # Visual Studio 15
VisualStudioVersion = 15.0.26430.6 VisualStudioVersion = 15.0.26430.13
MinimumVisualStudioVersion = 10.0.40219.1 MinimumVisualStudioVersion = 10.0.40219.1
Project("{2150E333-8FDC-42A3-9474-1A3956D46DE8}") = "src", "src", "{9B2AE124-6636-4DE9-83A3-70360DABD0C4}" Project("{2150E333-8FDC-42A3-9474-1A3956D46DE8}") = "src", "src", "{9B2AE124-6636-4DE9-83A3-70360DABD0C4}"
EndProject EndProject
Project("{2150E333-8FDC-42A3-9474-1A3956D46DE8}") = "test", "test", "{C09CDAB0-6DD4-46E9-B7F3-3EF2A4741EA0}" Project("{2150E333-8FDC-42A3-9474-1A3956D46DE8}") = "test", "test", "{C09CDAB0-6DD4-46E9-B7F3-3EF2A4741EA0}"
EndProject EndProject
Project("{2150E333-8FDC-42A3-9474-1A3956D46DE8}") = "Solution Items", "Solution Items", "{57A8A8E5-5715-41BF-A0A6-46B819933FBC}" Project("{2150E333-8FDC-42A3-9474-1A3956D46DE8}") = "Solution Items", "Solution Items", "{57A8A8E5-5715-41BF-A0A6-46B819933FBC}"
ProjectSection(SolutionItems) = preProject
CAP.vssettings = CAP.vssettings
EndProjectSection
EndProject EndProject
Project("{2150E333-8FDC-42A3-9474-1A3956D46DE8}") = "Shared", "Shared", "{9E5A7F49-8E31-4A71-90CC-1DA9AEDA99EE}" Project("{2150E333-8FDC-42A3-9474-1A3956D46DE8}") = "Shared", "Shared", "{9E5A7F49-8E31-4A71-90CC-1DA9AEDA99EE}"
ProjectSection(SolutionItems) = preProject ProjectSection(SolutionItems) = preProject
...@@ -18,21 +21,17 @@ Project("{2150E333-8FDC-42A3-9474-1A3956D46DE8}") = "Shared", "Shared", "{9E5A7F ...@@ -18,21 +21,17 @@ Project("{2150E333-8FDC-42A3-9474-1A3956D46DE8}") = "Shared", "Shared", "{9E5A7F
{82A7F48D-3B50-4B1E-B82E-3ADA8210C358} = {82A7F48D-3B50-4B1E-B82E-3ADA8210C358} {82A7F48D-3B50-4B1E-B82E-3ADA8210C358} = {82A7F48D-3B50-4B1E-B82E-3ADA8210C358}
EndProjectSection EndProjectSection
EndProject EndProject
Project("{9A19103F-16F7-4668-BE54-9A1E7A4F7556}") = "Cap.Consistency", "src\Cap.Consistency\Cap.Consistency.csproj", "{E8AF8611-0EA4-4B19-BC48-87C57A87DC66}" 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}") = "Cap.Consistency.Test", "test\Cap.Consistency.Test\Cap.Consistency.Test.csproj", "{3A444CF8-1611-407F-8D32-5D0CDC3DD49D}"
EndProject EndProject
Project("{9A19103F-16F7-4668-BE54-9A1E7A4F7556}") = "Cap.Consistency.EntityFrameworkCore", "src\Cap.Consistency.EntityFrameworkCore\Cap.Consistency.EntityFrameworkCore.csproj", "{96111249-C4C3-4DC9-A887-32D583723AB1}" Project("{9A19103F-16F7-4668-BE54-9A1E7A4F7556}") = "DotNetCore.CAP.EntityFrameworkCore", "src\DotNetCore.CAP.EntityFrameworkCore\DotNetCore.CAP.EntityFrameworkCore.csproj", "{96111249-C4C3-4DC9-A887-32D583723AB1}"
EndProject
Project("{9A19103F-16F7-4668-BE54-9A1E7A4F7556}") = "Cap.Consistency.EntityFrameworkCore.Test", "test\Cap.Consistency.EntityFrameworkCore.Test\Cap.Consistency.EntityFrameworkCore.Test.csproj", "{7442C942-1DDC-40E4-8F1B-654E721EAA45}"
EndProject EndProject
Project("{2150E333-8FDC-42A3-9474-1A3956D46DE8}") = "samples", "samples", "{3A6B6931-A123-477A-9469-8B468B5385AF}" Project("{2150E333-8FDC-42A3-9474-1A3956D46DE8}") = "samples", "samples", "{3A6B6931-A123-477A-9469-8B468B5385AF}"
EndProject EndProject
Project("{FAE04EC0-301F-11D3-BF4B-00C04F79EFBC}") = "Sample.Kafka", "samples\Sample.Kafka\Sample.Kafka.csproj", "{2F095ED9-5BC9-4512-9013-A47685FB2508}" Project("{FAE04EC0-301F-11D3-BF4B-00C04F79EFBC}") = "Sample.Kafka", "samples\Sample.Kafka\Sample.Kafka.csproj", "{2F095ED9-5BC9-4512-9013-A47685FB2508}"
EndProject EndProject
Project("{FAE04EC0-301F-11D3-BF4B-00C04F79EFBC}") = "Cap.Consistency.Kafka", "src\Cap.Consistency.Kafka\Cap.Consistency.Kafka.csproj", "{C42CDE33-0878-4BA0-96F2-4CB7C8FDEAAD}" Project("{FAE04EC0-301F-11D3-BF4B-00C04F79EFBC}") = "DotNetCore.CAP.Kafka", "src\DotNetCore.CAP.Kafka\DotNetCore.CAP.Kafka.csproj", "{C42CDE33-0878-4BA0-96F2-4CB7C8FDEAAD}"
EndProject EndProject
Project("{FAE04EC0-301F-11D3-BF4B-00C04F79EFBC}") = "Cap.Consistency.RabbitMQ", "src\Cap.Consistency.RabbitMQ\Cap.Consistency.RabbitMQ.csproj", "{9961B80E-0718-4280-B2A0-271B003DE26B}" Project("{FAE04EC0-301F-11D3-BF4B-00C04F79EFBC}") = "DotNetCore.CAP.RabbitMQ", "src\DotNetCore.CAP.RabbitMQ\DotNetCore.CAP.RabbitMQ.csproj", "{9961B80E-0718-4280-B2A0-271B003DE26B}"
EndProject EndProject
Project("{2150E333-8FDC-42A3-9474-1A3956D46DE8}") = "build", "build", "{10C0818D-9160-4B80-BB86-DDE925B64D43}" Project("{2150E333-8FDC-42A3-9474-1A3956D46DE8}") = "build", "build", "{10C0818D-9160-4B80-BB86-DDE925B64D43}"
ProjectSection(SolutionItems) = preProject ProjectSection(SolutionItems) = preProject
...@@ -46,6 +45,10 @@ Project("{2150E333-8FDC-42A3-9474-1A3956D46DE8}") = "build", "build", "{10C0818D ...@@ -46,6 +45,10 @@ Project("{2150E333-8FDC-42A3-9474-1A3956D46DE8}") = "build", "build", "{10C0818D
build\version.props = build\version.props build\version.props = build\version.props
EndProjectSection EndProjectSection
EndProject 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
Global Global
GlobalSection(SolutionConfigurationPlatforms) = preSolution GlobalSection(SolutionConfigurationPlatforms) = preSolution
Debug|Any CPU = Debug|Any CPU Debug|Any CPU = Debug|Any CPU
...@@ -56,18 +59,10 @@ Global ...@@ -56,18 +59,10 @@ Global
{E8AF8611-0EA4-4B19-BC48-87C57A87DC66}.Debug|Any CPU.Build.0 = Debug|Any CPU {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.ActiveCfg = Release|Any CPU
{E8AF8611-0EA4-4B19-BC48-87C57A87DC66}.Release|Any CPU.Build.0 = Release|Any CPU {E8AF8611-0EA4-4B19-BC48-87C57A87DC66}.Release|Any CPU.Build.0 = Release|Any CPU
{3A444CF8-1611-407F-8D32-5D0CDC3DD49D}.Debug|Any CPU.ActiveCfg = Debug|Any CPU
{3A444CF8-1611-407F-8D32-5D0CDC3DD49D}.Debug|Any CPU.Build.0 = Debug|Any CPU
{3A444CF8-1611-407F-8D32-5D0CDC3DD49D}.Release|Any CPU.ActiveCfg = Release|Any CPU
{3A444CF8-1611-407F-8D32-5D0CDC3DD49D}.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.ActiveCfg = Debug|Any CPU
{96111249-C4C3-4DC9-A887-32D583723AB1}.Debug|Any CPU.Build.0 = 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.ActiveCfg = Release|Any CPU
{96111249-C4C3-4DC9-A887-32D583723AB1}.Release|Any CPU.Build.0 = Release|Any CPU {96111249-C4C3-4DC9-A887-32D583723AB1}.Release|Any CPU.Build.0 = Release|Any CPU
{7442C942-1DDC-40E4-8F1B-654E721EAA45}.Debug|Any CPU.ActiveCfg = Debug|Any CPU
{7442C942-1DDC-40E4-8F1B-654E721EAA45}.Debug|Any CPU.Build.0 = Debug|Any CPU
{7442C942-1DDC-40E4-8F1B-654E721EAA45}.Release|Any CPU.ActiveCfg = Release|Any CPU
{7442C942-1DDC-40E4-8F1B-654E721EAA45}.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.ActiveCfg = Debug|Any CPU
{2F095ED9-5BC9-4512-9013-A47685FB2508}.Debug|Any CPU.Build.0 = 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 {2F095ED9-5BC9-4512-9013-A47685FB2508}.Release|Any CPU.ActiveCfg = Release|Any CPU
...@@ -80,6 +75,14 @@ Global ...@@ -80,6 +75,14 @@ Global
{9961B80E-0718-4280-B2A0-271B003DE26B}.Debug|Any CPU.Build.0 = Debug|Any CPU {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.ActiveCfg = Release|Any CPU
{9961B80E-0718-4280-B2A0-271B003DE26B}.Release|Any CPU.Build.0 = 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
{F608B509-A99B-4AC7-8227-42051DD4A578}.Release|Any CPU.Build.0 = Release|Any CPU
EndGlobalSection EndGlobalSection
GlobalSection(SolutionProperties) = preSolution GlobalSection(SolutionProperties) = preSolution
HideSolutionNode = FALSE HideSolutionNode = FALSE
...@@ -87,11 +90,11 @@ Global ...@@ -87,11 +90,11 @@ Global
GlobalSection(NestedProjects) = preSolution GlobalSection(NestedProjects) = preSolution
{9E5A7F49-8E31-4A71-90CC-1DA9AEDA99EE} = {C09CDAB0-6DD4-46E9-B7F3-3EF2A4741EA0} {9E5A7F49-8E31-4A71-90CC-1DA9AEDA99EE} = {C09CDAB0-6DD4-46E9-B7F3-3EF2A4741EA0}
{E8AF8611-0EA4-4B19-BC48-87C57A87DC66} = {9B2AE124-6636-4DE9-83A3-70360DABD0C4} {E8AF8611-0EA4-4B19-BC48-87C57A87DC66} = {9B2AE124-6636-4DE9-83A3-70360DABD0C4}
{3A444CF8-1611-407F-8D32-5D0CDC3DD49D} = {C09CDAB0-6DD4-46E9-B7F3-3EF2A4741EA0}
{96111249-C4C3-4DC9-A887-32D583723AB1} = {9B2AE124-6636-4DE9-83A3-70360DABD0C4} {96111249-C4C3-4DC9-A887-32D583723AB1} = {9B2AE124-6636-4DE9-83A3-70360DABD0C4}
{7442C942-1DDC-40E4-8F1B-654E721EAA45} = {C09CDAB0-6DD4-46E9-B7F3-3EF2A4741EA0}
{2F095ED9-5BC9-4512-9013-A47685FB2508} = {3A6B6931-A123-477A-9469-8B468B5385AF} {2F095ED9-5BC9-4512-9013-A47685FB2508} = {3A6B6931-A123-477A-9469-8B468B5385AF}
{C42CDE33-0878-4BA0-96F2-4CB7C8FDEAAD} = {9B2AE124-6636-4DE9-83A3-70360DABD0C4} {C42CDE33-0878-4BA0-96F2-4CB7C8FDEAAD} = {9B2AE124-6636-4DE9-83A3-70360DABD0C4}
{9961B80E-0718-4280-B2A0-271B003DE26B} = {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}
EndGlobalSection EndGlobalSection
EndGlobal EndGlobal
...@@ -2,7 +2,7 @@ ...@@ -2,7 +2,7 @@
using System.Collections.Generic; using System.Collections.Generic;
using System.Linq; using System.Linq;
using System.Threading.Tasks; using System.Threading.Tasks;
using Cap.Consistency.Infrastructure; using DotNetCore.CAP.Infrastructure;
using JetBrains.Annotations; using JetBrains.Annotations;
using Microsoft.EntityFrameworkCore; using Microsoft.EntityFrameworkCore;
......
using System; using System;
using System.Threading.Tasks; using System.Threading.Tasks;
using Cap.Consistency; using DotNetCore.CAP;
using Cap.Consistency.Consumer; using DotNetCore.CAP.Kafka;
using Cap.Consistency.Kafka;
using Microsoft.AspNetCore.Mvc; using Microsoft.AspNetCore.Mvc;
namespace Sample.Kafka.Controllers namespace Sample.Kafka.Controllers
...@@ -10,9 +9,9 @@ namespace Sample.Kafka.Controllers ...@@ -10,9 +9,9 @@ namespace Sample.Kafka.Controllers
[Route("api/[controller]")] [Route("api/[controller]")]
public class ValuesController : Controller, IConsumerService public class ValuesController : Controller, IConsumerService
{ {
private readonly IProducerClient _producer; private readonly ICapProducerService _producer;
public ValuesController(IProducerClient producer) { public ValuesController(ICapProducerService producer) {
_producer = producer; _producer = producer;
} }
......
...@@ -4,7 +4,7 @@ using Microsoft.EntityFrameworkCore.Infrastructure; ...@@ -4,7 +4,7 @@ using Microsoft.EntityFrameworkCore.Infrastructure;
using Microsoft.EntityFrameworkCore.Metadata; using Microsoft.EntityFrameworkCore.Metadata;
using Microsoft.EntityFrameworkCore.Migrations; using Microsoft.EntityFrameworkCore.Migrations;
using Sample.Kafka; using Sample.Kafka;
using Cap.Consistency.Infrastructure; using DotNetCore.CAP.Infrastructure;
namespace Sample.Kafka.Migrations namespace Sample.Kafka.Migrations
{ {
...@@ -18,7 +18,7 @@ namespace Sample.Kafka.Migrations ...@@ -18,7 +18,7 @@ namespace Sample.Kafka.Migrations
.HasAnnotation("ProductVersion", "1.1.2") .HasAnnotation("ProductVersion", "1.1.2")
.HasAnnotation("SqlServer:ValueGenerationStrategy", SqlServerValueGenerationStrategy.IdentityColumn); .HasAnnotation("SqlServer:ValueGenerationStrategy", SqlServerValueGenerationStrategy.IdentityColumn);
modelBuilder.Entity("Cap.Consistency.Infrastructure.ConsistencyMessage", b => modelBuilder.Entity("DotNetCore.CAP.Infrastructure.ConsistencyMessage", b =>
{ {
b.Property<string>("Id") b.Property<string>("Id")
.ValueGeneratedOnAdd(); .ValueGeneratedOnAdd();
......
...@@ -4,7 +4,7 @@ using Microsoft.EntityFrameworkCore.Infrastructure; ...@@ -4,7 +4,7 @@ using Microsoft.EntityFrameworkCore.Infrastructure;
using Microsoft.EntityFrameworkCore.Metadata; using Microsoft.EntityFrameworkCore.Metadata;
using Microsoft.EntityFrameworkCore.Migrations; using Microsoft.EntityFrameworkCore.Migrations;
using Sample.Kafka; using Sample.Kafka;
using Cap.Consistency.Infrastructure; using DotNetCore.CAP.Infrastructure;
namespace Sample.Kafka.Migrations namespace Sample.Kafka.Migrations
{ {
...@@ -17,7 +17,7 @@ namespace Sample.Kafka.Migrations ...@@ -17,7 +17,7 @@ namespace Sample.Kafka.Migrations
.HasAnnotation("ProductVersion", "1.1.2") .HasAnnotation("ProductVersion", "1.1.2")
.HasAnnotation("SqlServer:ValueGenerationStrategy", SqlServerValueGenerationStrategy.IdentityColumn); .HasAnnotation("SqlServer:ValueGenerationStrategy", SqlServerValueGenerationStrategy.IdentityColumn);
modelBuilder.Entity("Cap.Consistency.Infrastructure.ConsistencyMessage", b => modelBuilder.Entity("DotNetCore.CAP.Infrastructure.ConsistencyMessage", b =>
{ {
b.Property<string>("Id") b.Property<string>("Id")
.ValueGeneratedOnAdd(); .ValueGeneratedOnAdd();
......
...@@ -23,10 +23,10 @@ ...@@ -23,10 +23,10 @@
<DotNetCliToolReference Include="Microsoft.EntityFrameworkCore.Tools.DotNet" Version="1.0.0" /> <DotNetCliToolReference Include="Microsoft.EntityFrameworkCore.Tools.DotNet" Version="1.0.0" />
</ItemGroup> </ItemGroup>
<ItemGroup> <ItemGroup>
<ProjectReference Include="..\..\src\Cap.Consistency.EntityFrameworkCore\Cap.Consistency.EntityFrameworkCore.csproj" /> <ProjectReference Include="..\..\src\DotNetCore.CAP.EntityFrameworkCore\DotNetCore.CAP.EntityFrameworkCore.csproj" />
<ProjectReference Include="..\..\src\Cap.Consistency.Kafka\Cap.Consistency.Kafka.csproj" /> <ProjectReference Include="..\..\src\DotNetCore.CAP.Kafka\DotNetCore.CAP.Kafka.csproj" />
<ProjectReference Include="..\..\src\Cap.Consistency.RabbitMQ\Cap.Consistency.RabbitMQ.csproj" /> <ProjectReference Include="..\..\src\DotNetCore.CAP.RabbitMQ\DotNetCore.CAP.RabbitMQ.csproj" />
<ProjectReference Include="..\..\src\Cap.Consistency\Cap.Consistency.csproj" /> <ProjectReference Include="..\..\src\DotNetCore.CAP\DotNetCore.CAP.csproj" />
</ItemGroup> </ItemGroup>
</Project> </Project>
using System;
using System.Collections.Generic;
using System.Text;
using System.Threading.Tasks;
using Cap.Consistency.Infrastructure;
namespace Cap.Consistency
{
public interface IProducerClient
{
Task SendAsync(string topic, string content);
}
}
using System; using DotNetCore.CAP.Infrastructure;
using Cap.Consistency.Infrastructure;
using Microsoft.EntityFrameworkCore; using Microsoft.EntityFrameworkCore;
namespace Cap.Consistency.EntityFrameworkCore namespace DotNetCore.CAP.EntityFrameworkCore
{ {
/// <summary> /// <summary>
/// Base class for the Entity Framework database context used for consistency. /// Base class for the Entity Framework database context used for consistency.
...@@ -33,8 +32,10 @@ namespace Cap.Consistency.EntityFrameworkCore ...@@ -33,8 +32,10 @@ namespace Cap.Consistency.EntityFrameworkCore
/// <param name="modelBuilder"> /// <param name="modelBuilder">
/// The builder being used to construct the model for this context. /// The builder being used to construct the model for this context.
/// </param> /// </param>
protected override void OnModelCreating(ModelBuilder modelBuilder) { protected override void OnModelCreating(ModelBuilder modelBuilder)
modelBuilder.Entity<ConsistencyMessage>(b => { {
modelBuilder.Entity<ConsistencyMessage>(b =>
{
b.HasKey(m => m.Id); b.HasKey(m => m.Id);
b.ToTable("ConsistencyMessages"); b.ToTable("ConsistencyMessages");
}); });
......
using Cap.Consistency; using DotNetCore.CAP;
using Cap.Consistency.EntityFrameworkCore; using DotNetCore.CAP.EntityFrameworkCore;
using Microsoft.EntityFrameworkCore; using Microsoft.EntityFrameworkCore;
namespace Microsoft.Extensions.DependencyInjection namespace Microsoft.Extensions.DependencyInjection
{ {
/// <summary> /// <summary>
/// Contains extension methods to <see cref="ConsistencyBuilder"/> for adding entity framework stores. /// Contains extension methods to <see cref="CapBuilder"/> for adding entity framework stores.
/// </summary> /// </summary>
public static class ConsistencyEntityFrameworkBuilderExtensions public static class ConsistencyEntityFrameworkBuilderExtensions
{ {
...@@ -13,11 +13,12 @@ namespace Microsoft.Extensions.DependencyInjection ...@@ -13,11 +13,12 @@ namespace Microsoft.Extensions.DependencyInjection
/// Adds an Entity Framework implementation of message stores. /// Adds an Entity Framework implementation of message stores.
/// </summary> /// </summary>
/// <typeparam name="TContext">The Entity Framework database context to use.</typeparam> /// <typeparam name="TContext">The Entity Framework database context to use.</typeparam>
/// <param name="services">The <see cref="ConsistencyBuilder"/> instance this method extends.</param> /// <param name="services">The <see cref="CapBuilder"/> instance this method extends.</param>
/// <returns>The <see cref="ConsistencyBuilder"/> instance this method extends.</returns> /// <returns>The <see cref="CapBuilder"/> instance this method extends.</returns>
public static ConsistencyBuilder AddEntityFrameworkStores<TContext>(this ConsistencyBuilder builder) public static CapBuilder AddEntityFrameworkStores<TContext>(this CapBuilder builder)
where TContext : DbContext { where TContext : DbContext
builder.Services.AddScoped<IConsistencyMessageStore, ConsistencyMessageStore<TContext>>(); {
builder.Services.AddScoped<ICapMessageStore, ConsistencyMessageStore<TContext>>();
return builder; return builder;
} }
......
...@@ -2,10 +2,10 @@ ...@@ -2,10 +2,10 @@
using System.Linq; using System.Linq;
using System.Threading; using System.Threading;
using System.Threading.Tasks; using System.Threading.Tasks;
using Cap.Consistency.Infrastructure; using DotNetCore.CAP.Infrastructure;
using Microsoft.EntityFrameworkCore; using Microsoft.EntityFrameworkCore;
namespace Cap.Consistency.EntityFrameworkCore namespace DotNetCore.CAP.EntityFrameworkCore
{ {
/// <summary> /// <summary>
/// Represents a new instance of a persistence store for the specified message types. /// Represents a new instance of a persistence store for the specified message types.
...@@ -13,7 +13,7 @@ namespace Cap.Consistency.EntityFrameworkCore ...@@ -13,7 +13,7 @@ namespace Cap.Consistency.EntityFrameworkCore
/// <typeparam name="ConsistencyMessage">The type representing a message.</typeparam> /// <typeparam name="ConsistencyMessage">The type representing a message.</typeparam>
/// <typeparam name="TContext">The type of the data context class used to access the store.</typeparam> /// <typeparam name="TContext">The type of the data context class used to access the store.</typeparam>
/// <typeparam name="TKey">The type of the primary key for a message.</typeparam> /// <typeparam name="TKey">The type of the primary key for a message.</typeparam>
public class ConsistencyMessageStore<TContext> : IConsistencyMessageStore where TContext : DbContext public class ConsistencyMessageStore<TContext> : ICapMessageStore where TContext : DbContext
{ {
private bool _disposed; private bool _disposed;
...@@ -21,8 +21,10 @@ namespace Cap.Consistency.EntityFrameworkCore ...@@ -21,8 +21,10 @@ namespace Cap.Consistency.EntityFrameworkCore
/// Constructs a new instance of <see cref="ConsistencyMessageStore{ConsistencyMessage, TContext, TKey}"/>. /// Constructs a new instance of <see cref="ConsistencyMessageStore{ConsistencyMessage, TContext, TKey}"/>.
/// </summary> /// </summary>
/// <param name="context">The <see cref="DbContext"/>.</param> /// <param name="context">The <see cref="DbContext"/>.</param>
public ConsistencyMessageStore(TContext context) { public ConsistencyMessageStore(TContext context)
if (context == null) { {
if (context == null)
{
throw new ArgumentNullException(nameof(context)); throw new ArgumentNullException(nameof(context));
} }
Context = context; Context = context;
...@@ -38,10 +40,12 @@ namespace Cap.Consistency.EntityFrameworkCore ...@@ -38,10 +40,12 @@ namespace Cap.Consistency.EntityFrameworkCore
/// <param name="message">The message to create.</param> /// <param name="message">The message to create.</param>
/// <param name="cancellationToken">The <see cref="CancellationToken"/> used to propagate notifications that the operation should be canceled.</param> /// <param name="cancellationToken">The <see cref="CancellationToken"/> used to propagate notifications that the operation should be canceled.</param>
/// <returns>The <see cref="Task"/> that represents the asynchronous operation, containing the <see cref="OperateResult"/> of the creation operation.</returns> /// <returns>The <see cref="Task"/> that represents the asynchronous operation, containing the <see cref="OperateResult"/> of the creation operation.</returns>
public async virtual Task<OperateResult> CreateAsync(ConsistencyMessage message, CancellationToken cancellationToken) { public async virtual Task<OperateResult> CreateAsync(ConsistencyMessage message, CancellationToken cancellationToken)
{
cancellationToken.ThrowIfCancellationRequested(); cancellationToken.ThrowIfCancellationRequested();
ThrowIfDisposed(); ThrowIfDisposed();
if (message == null) { if (message == null)
{
throw new ArgumentNullException(nameof(message)); throw new ArgumentNullException(nameof(message));
} }
Context.Add(message); Context.Add(message);
...@@ -55,18 +59,22 @@ namespace Cap.Consistency.EntityFrameworkCore ...@@ -55,18 +59,22 @@ namespace Cap.Consistency.EntityFrameworkCore
/// <param name="message">The message to delete.</param> /// <param name="message">The message to delete.</param>
/// <param name="cancellationToken">The <see cref="CancellationToken"/> used to propagate notifications that the operation should be canceled.</param> /// <param name="cancellationToken">The <see cref="CancellationToken"/> used to propagate notifications that the operation should be canceled.</param>
/// <returns>The <see cref="Task"/> that represents the asynchronous operation, containing the <see cref="OperateResult"/> of the update operation.</returns> /// <returns>The <see cref="Task"/> that represents the asynchronous operation, containing the <see cref="OperateResult"/> of the update operation.</returns>
public async virtual Task<OperateResult> DeleteAsync(ConsistencyMessage message, CancellationToken cancellationToken) { public async virtual Task<OperateResult> DeleteAsync(ConsistencyMessage message, CancellationToken cancellationToken)
{
cancellationToken.ThrowIfCancellationRequested(); cancellationToken.ThrowIfCancellationRequested();
ThrowIfDisposed(); ThrowIfDisposed();
if (message == null) { if (message == null)
{
throw new ArgumentNullException(nameof(message)); throw new ArgumentNullException(nameof(message));
} }
Context.Remove(message); Context.Remove(message);
try { try
{
await SaveChanges(cancellationToken); await SaveChanges(cancellationToken);
} }
catch (DbUpdateConcurrencyException ex) { catch (DbUpdateConcurrencyException ex)
{
return OperateResult.Failed(new OperateError() { Code = "DbUpdateConcurrencyException", Description = ex.Message }); return OperateResult.Failed(new OperateError() { Code = "DbUpdateConcurrencyException", Description = ex.Message });
} }
return OperateResult.Success; return OperateResult.Success;
...@@ -80,7 +88,8 @@ namespace Cap.Consistency.EntityFrameworkCore ...@@ -80,7 +88,8 @@ namespace Cap.Consistency.EntityFrameworkCore
/// <returns> /// <returns>
/// The <see cref="Task"/> that represents the asynchronous operation, containing the message matching the specified <paramref name="messageId"/> if it exists. /// The <see cref="Task"/> that represents the asynchronous operation, containing the message matching the specified <paramref name="messageId"/> if it exists.
/// </returns> /// </returns>
public virtual Task<ConsistencyMessage> FindByIdAsync(string messageId, CancellationToken cancellationToken) { public virtual Task<ConsistencyMessage> FindByIdAsync(string messageId, CancellationToken cancellationToken)
{
cancellationToken.ThrowIfCancellationRequested(); cancellationToken.ThrowIfCancellationRequested();
ThrowIfDisposed(); ThrowIfDisposed();
return MessageSet.FindAsync(new object[] { messageId }, cancellationToken); return MessageSet.FindAsync(new object[] { messageId }, cancellationToken);
...@@ -92,10 +101,12 @@ namespace Cap.Consistency.EntityFrameworkCore ...@@ -92,10 +101,12 @@ namespace Cap.Consistency.EntityFrameworkCore
/// <param name="message">The message whose identifier should be retrieved.</param> /// <param name="message">The message whose identifier should be retrieved.</param>
/// <param name="cancellationToken">The <see cref="CancellationToken"/> used to propagate notifications that the operation should be canceled.</param> /// <param name="cancellationToken">The <see cref="CancellationToken"/> used to propagate notifications that the operation should be canceled.</param>
/// <returns>The <see cref="Task"/> that represents the asynchronous operation, containing the identifier for the specified <paramref name="message"/>.</returns> /// <returns>The <see cref="Task"/> that represents the asynchronous operation, containing the identifier for the specified <paramref name="message"/>.</returns>
public Task<string> GeConsistencyMessageIdAsync(ConsistencyMessage message, CancellationToken cancellationToken) { public Task<string> GeConsistencyMessageIdAsync(ConsistencyMessage message, CancellationToken cancellationToken)
{
cancellationToken.ThrowIfCancellationRequested(); cancellationToken.ThrowIfCancellationRequested();
ThrowIfDisposed(); ThrowIfDisposed();
if (message == null) { if (message == null)
{
throw new ArgumentNullException(nameof(message)); throw new ArgumentNullException(nameof(message));
} }
return Task.FromResult(message.Id); return Task.FromResult(message.Id);
...@@ -107,26 +118,31 @@ namespace Cap.Consistency.EntityFrameworkCore ...@@ -107,26 +118,31 @@ namespace Cap.Consistency.EntityFrameworkCore
/// <param name="message">The message to update.</param> /// <param name="message">The message to update.</param>
/// <param name="cancellationToken">The <see cref="CancellationToken"/> used to propagate notifications that the operation should be canceled.</param> /// <param name="cancellationToken">The <see cref="CancellationToken"/> used to propagate notifications that the operation should be canceled.</param>
/// <returns>The <see cref="Task"/> that represents the asynchronous operation, containing the <see cref="OperateResult"/> of the update operation.</returns> /// <returns>The <see cref="Task"/> that represents the asynchronous operation, containing the <see cref="OperateResult"/> of the update operation.</returns>
public async virtual Task<OperateResult> UpdateAsync(ConsistencyMessage message, CancellationToken cancellationToken) { public async virtual Task<OperateResult> UpdateAsync(ConsistencyMessage message, CancellationToken cancellationToken)
{
cancellationToken.ThrowIfCancellationRequested(); cancellationToken.ThrowIfCancellationRequested();
ThrowIfDisposed(); ThrowIfDisposed();
if (message == null) { if (message == null)
{
throw new ArgumentNullException(nameof(message)); throw new ArgumentNullException(nameof(message));
} }
Context.Attach(message); Context.Attach(message);
message.UpdateTime = DateTime.Now; message.UpdateTime = DateTime.Now;
Context.Update(message); Context.Update(message);
try { try
{
await SaveChanges(cancellationToken); await SaveChanges(cancellationToken);
} }
catch (DbUpdateConcurrencyException ex) { catch (DbUpdateConcurrencyException ex)
{
return OperateResult.Failed(new OperateError() { Code = "DbUpdateConcurrencyException", Description = ex.Message }); return OperateResult.Failed(new OperateError() { Code = "DbUpdateConcurrencyException", Description = ex.Message });
} }
return OperateResult.Success; return OperateResult.Success;
} }
public Task<ConsistencyMessage> GetFirstEnqueuedMessageAsync(CancellationToken cancellationToken) { public Task<ConsistencyMessage> GetFirstEnqueuedMessageAsync(CancellationToken cancellationToken)
{
cancellationToken.ThrowIfCancellationRequested(); cancellationToken.ThrowIfCancellationRequested();
return MessageSet.AsNoTracking().Where(x => x.Status == MessageStatus.WaitForSend).FirstOrDefaultAsync(cancellationToken); return MessageSet.AsNoTracking().Where(x => x.Status == MessageStatus.WaitForSend).FirstOrDefaultAsync(cancellationToken);
} }
...@@ -155,15 +171,18 @@ namespace Cap.Consistency.EntityFrameworkCore ...@@ -155,15 +171,18 @@ namespace Cap.Consistency.EntityFrameworkCore
/// <summary>Saves the current store.</summary> /// <summary>Saves the current store.</summary>
/// <param name="cancellationToken">The <see cref="CancellationToken"/> used to propagate notifications that the operation should be canceled.</param> /// <param name="cancellationToken">The <see cref="CancellationToken"/> used to propagate notifications that the operation should be canceled.</param>
/// <returns>The <see cref="Task"/> that represents the asynchronous operation.</returns> /// <returns>The <see cref="Task"/> that represents the asynchronous operation.</returns>
protected Task SaveChanges(CancellationToken cancellationToken) { protected Task SaveChanges(CancellationToken cancellationToken)
{
return AutoSaveChanges ? Context.SaveChangesAsync(cancellationToken) : Task.CompletedTask; return AutoSaveChanges ? Context.SaveChangesAsync(cancellationToken) : Task.CompletedTask;
} }
/// <summary> /// <summary>
/// Throws if this class has been disposed. /// Throws if this class has been disposed.
/// </summary> /// </summary>
protected void ThrowIfDisposed() { protected void ThrowIfDisposed()
if (_disposed) { {
if (_disposed)
{
throw new ObjectDisposedException(GetType().Name); throw new ObjectDisposedException(GetType().Name);
} }
} }
...@@ -171,7 +190,8 @@ namespace Cap.Consistency.EntityFrameworkCore ...@@ -171,7 +190,8 @@ namespace Cap.Consistency.EntityFrameworkCore
/// <summary> /// <summary>
/// Dispose the store /// Dispose the store
/// </summary> /// </summary>
public void Dispose() { public void Dispose()
{
_disposed = true; _disposed = true;
} }
} }
......
...@@ -2,8 +2,8 @@ ...@@ -2,8 +2,8 @@
<PropertyGroup> <PropertyGroup>
<TargetFramework>netstandard1.6</TargetFramework> <TargetFramework>netstandard1.6</TargetFramework>
<AssemblyName>Cap.Consistency.EntityFrameworkCore</AssemblyName> <AssemblyName>DotNetCore.CAP.EntityFrameworkCore</AssemblyName>
<PackageId>Cap.Consistency.EntityFrameworkCore</PackageId> <PackageId>DotNetCore.CAP.EntityFrameworkCore</PackageId>
<NetStandardImplicitPackageVersion>1.6.1</NetStandardImplicitPackageVersion> <NetStandardImplicitPackageVersion>1.6.1</NetStandardImplicitPackageVersion>
<PackageTargetFallback>$(PackageTargetFallback);dnxcore50</PackageTargetFallback> <PackageTargetFallback>$(PackageTargetFallback);dnxcore50</PackageTargetFallback>
<GenerateAssemblyConfigurationAttribute>false</GenerateAssemblyConfigurationAttribute> <GenerateAssemblyConfigurationAttribute>false</GenerateAssemblyConfigurationAttribute>
...@@ -11,14 +11,14 @@ ...@@ -11,14 +11,14 @@
<GenerateAssemblyProductAttribute>false</GenerateAssemblyProductAttribute> <GenerateAssemblyProductAttribute>false</GenerateAssemblyProductAttribute>
</PropertyGroup> </PropertyGroup>
<ItemGroup>
<ProjectReference Include="..\Cap.Consistency\Cap.Consistency.csproj" />
</ItemGroup>
<ItemGroup> <ItemGroup>
<PackageReference Include="Microsoft.EntityFrameworkCore" Version="1.1.2" /> <PackageReference Include="Microsoft.EntityFrameworkCore" Version="1.1.2" />
<PackageReference Include="Microsoft.EntityFrameworkCore.Relational" Version="1.1.2" /> <PackageReference Include="Microsoft.EntityFrameworkCore.Relational" Version="1.1.2" />
<PackageReference Include="System.ComponentModel.TypeConverter" Version="4.3.0" /> <PackageReference Include="System.ComponentModel.TypeConverter" Version="4.3.0" />
</ItemGroup> </ItemGroup>
<ItemGroup>
<ProjectReference Include="..\DotNetCore.CAP\DotNetCore.CAP.csproj" />
</ItemGroup>
</Project> </Project>
...@@ -3,6 +3,12 @@ ...@@ -3,6 +3,12 @@
<PropertyGroup> <PropertyGroup>
<TargetFramework>netstandard1.6</TargetFramework> <TargetFramework>netstandard1.6</TargetFramework>
<NetStandardImplicitPackageVersion>1.6.1</NetStandardImplicitPackageVersion> <NetStandardImplicitPackageVersion>1.6.1</NetStandardImplicitPackageVersion>
<AssemblyName>DotNetCore.CAP.Kafka</AssemblyName>
<PackageId>DotNetCore.CAP.Kafka</PackageId>
<PackageTargetFallback>$(PackageTargetFallback);dnxcore50</PackageTargetFallback>
<GenerateAssemblyConfigurationAttribute>false</GenerateAssemblyConfigurationAttribute>
<GenerateAssemblyCompanyAttribute>false</GenerateAssemblyCompanyAttribute>
<GenerateAssemblyProductAttribute>false</GenerateAssemblyProductAttribute>
</PropertyGroup> </PropertyGroup>
<ItemGroup> <ItemGroup>
...@@ -10,7 +16,7 @@ ...@@ -10,7 +16,7 @@
</ItemGroup> </ItemGroup>
<ItemGroup> <ItemGroup>
<ProjectReference Include="..\Cap.Consistency\Cap.Consistency.csproj" /> <ProjectReference Include="..\DotNetCore.CAP\DotNetCore.CAP.csproj" />
</ItemGroup> </ItemGroup>
</Project> </Project>
\ No newline at end of file
...@@ -4,19 +4,18 @@ using System.Diagnostics; ...@@ -4,19 +4,18 @@ using System.Diagnostics;
using System.Text; using System.Text;
using System.Threading; using System.Threading;
using System.Threading.Tasks; using System.Threading.Tasks;
using Cap.Consistency.Infrastructure;
using Cap.Consistency.Job;
using Confluent.Kafka; using Confluent.Kafka;
using Confluent.Kafka.Serialization; using Confluent.Kafka.Serialization;
using DotNetCore.CAP.Infrastructure;
using DotNetCore.CAP.Job;
using Microsoft.Extensions.DependencyInjection; using Microsoft.Extensions.DependencyInjection;
using Microsoft.Extensions.Logging; using Microsoft.Extensions.Logging;
using Microsoft.Extensions.Options; using Microsoft.Extensions.Options;
namespace Cap.Consistency.Kafka namespace DotNetCore.CAP.Kafka
{ {
public class KafkaJobProcessor : IJobProcessor public class KafkaJobProcessor : IJobProcessor
{ {
private readonly ConsistencyOptions _options; private readonly ConsistencyOptions _options;
private readonly CancellationTokenSource _cts; private readonly CancellationTokenSource _cts;
...@@ -29,8 +28,8 @@ namespace Cap.Consistency.Kafka ...@@ -29,8 +28,8 @@ namespace Cap.Consistency.Kafka
public KafkaJobProcessor( public KafkaJobProcessor(
IOptions<ConsistencyOptions> options, IOptions<ConsistencyOptions> options,
ILogger<KafkaJobProcessor> logger, ILogger<KafkaJobProcessor> logger,
IServiceProvider provider) { IServiceProvider provider)
{
_logger = logger; _logger = logger;
_options = options.Value; _options = options.Value;
_provider = provider; _provider = provider;
...@@ -40,45 +39,53 @@ namespace Cap.Consistency.Kafka ...@@ -40,45 +39,53 @@ namespace Cap.Consistency.Kafka
public bool Waiting { get; private set; } public bool Waiting { get; private set; }
public Task ProcessAsync(ProcessingContext context) { public Task ProcessAsync(ProcessingContext context)
{
if (context == null) throw new ArgumentNullException(nameof(context)); if (context == null) throw new ArgumentNullException(nameof(context));
context.ThrowIfStopping(); context.ThrowIfStopping();
return ProcessCoreAsync(context); return ProcessCoreAsync(context);
} }
public async Task ProcessCoreAsync(ProcessingContext context) { public async Task ProcessCoreAsync(ProcessingContext context)
try { {
try
{
var worked = await Step(context); var worked = await Step(context);
context.ThrowIfStopping(); context.ThrowIfStopping();
Waiting = true; Waiting = true;
if (!worked) { if (!worked)
{
var token = GetTokenToWaitOn(context); var token = GetTokenToWaitOn(context);
} }
await WaitHandleEx.WaitAnyAsync(WaitHandleEx.PulseEvent, context.CancellationToken.WaitHandle, _pollingDelay); await WaitHandleEx.WaitAnyAsync(WaitHandleEx.PulseEvent, context.CancellationToken.WaitHandle, _pollingDelay);
} }
finally { finally
{
Waiting = false; Waiting = false;
} }
} }
protected virtual CancellationToken GetTokenToWaitOn(ProcessingContext context) { protected virtual CancellationToken GetTokenToWaitOn(ProcessingContext context)
{
return context.CancellationToken; return context.CancellationToken;
} }
private async Task<bool> Step(ProcessingContext context) { private async Task<bool> Step(ProcessingContext context)
using (var scopedContext = context.CreateScope()) { {
using (var scopedContext = context.CreateScope())
{
var provider = scopedContext.Provider; var provider = scopedContext.Provider;
var messageStore = provider.GetRequiredService<IConsistencyMessageStore>(); var messageStore = provider.GetRequiredService<ICapMessageStore>();
try { try
{
var message = await messageStore.GetFirstEnqueuedMessageAsync(_cts.Token); var message = await messageStore.GetFirstEnqueuedMessageAsync(_cts.Token);
if (message != null) { if (message != null)
{
var sp = Stopwatch.StartNew(); var sp = Stopwatch.StartNew();
message.Status = MessageStatus.Processing; message.Status = MessageStatus.Processing;
await messageStore.UpdateAsync(message, _cts.Token); await messageStore.UpdateAsync(message, _cts.Token);
...@@ -87,10 +94,12 @@ namespace Cap.Consistency.Kafka ...@@ -87,10 +94,12 @@ namespace Cap.Consistency.Kafka
sp.Stop(); sp.Stop();
if (!jobResult) { if (!jobResult)
{
_logger.JobFailed(new Exception("topic send failed")); _logger.JobFailed(new Exception("topic send failed"));
} }
else { else
{
message.Status = MessageStatus.Successed; message.Status = MessageStatus.Successed;
await messageStore.UpdateAsync(message, _cts.Token); await messageStore.UpdateAsync(message, _cts.Token);
//await messageStore.DeleteAsync(message, _cts.Token); //await messageStore.DeleteAsync(message, _cts.Token);
...@@ -98,31 +107,37 @@ namespace Cap.Consistency.Kafka ...@@ -98,31 +107,37 @@ namespace Cap.Consistency.Kafka
} }
} }
} }
catch (Exception ex) { catch (Exception )
{
return false; return false;
} }
} }
return true; return true;
} }
private bool ExecuteJob(string topic, string content) { private bool ExecuteJob(string topic, string content)
try { {
try
{
var config = new Dictionary<string, object> { { "bootstrap.servers", _options.BrokerUrlList } }; var config = new Dictionary<string, object> { { "bootstrap.servers", _options.BrokerUrlList } };
using (var producer = new Producer<Null, string>(config, null, new StringSerializer(Encoding.UTF8))) { using (var producer = new Producer<Null, string>(config, null, new StringSerializer(Encoding.UTF8)))
{
var message = producer.ProduceAsync(topic, null, content).Result; var message = producer.ProduceAsync(topic, null, content).Result;
if (message.Error.Code == ErrorCode.NoError) { if (message.Error.Code == ErrorCode.NoError)
{
return true; return true;
} }
else { else
{
return false; return false;
} }
} }
} }
catch (Exception ex) { catch (Exception ex)
{
_logger.ExceptionOccuredWhileExecutingJob(topic, ex); _logger.ExceptionOccuredWhileExecutingJob(topic, ex);
return false; return false;
} }
} }
} }
} }
\ No newline at end of file
using System; using System;
using System.Collections.Generic; using System.Collections.Generic;
using System.Text; using System.Text;
using Cap.Consistency.Consumer;
using Cap.Consistency.Infrastructure;
using Confluent.Kafka; using Confluent.Kafka;
using Confluent.Kafka.Serialization; using Confluent.Kafka.Serialization;
using DotNetCore.CAP.Infrastructure;
namespace Cap.Consistency.Kafka namespace DotNetCore.CAP.Kafka
{ {
public class KafkaConsumerClient : IConsumerClient public class KafkaConsumerClient : IConsumerClient
{ {
...@@ -19,38 +18,46 @@ namespace Cap.Consistency.Kafka ...@@ -19,38 +18,46 @@ namespace Cap.Consistency.Kafka
public IDeserializer<string> StringDeserializer { get; set; } public IDeserializer<string> StringDeserializer { get; set; }
public KafkaConsumerClient(string groupId, string bootstrapServers) { public KafkaConsumerClient(string groupId, string bootstrapServers)
{
_groupId = groupId; _groupId = groupId;
_bootstrapServers = bootstrapServers; _bootstrapServers = bootstrapServers;
StringDeserializer = new StringDeserializer(Encoding.UTF8); StringDeserializer = new StringDeserializer(Encoding.UTF8);
} }
public void Subscribe(string topic) { public void Subscribe(string topic)
{
Subscribe(topic, 0); Subscribe(topic, 0);
} }
public void Subscribe(string topicName, int partition) { public void Subscribe(string topicName, int partition)
if (_consumerClient == null) { {
if (_consumerClient == null)
{
InitKafkaClient(); InitKafkaClient();
} }
_consumerClient.Assignment.Add(new TopicPartition(topicName, partition)); _consumerClient.Assignment.Add(new TopicPartition(topicName, partition));
_consumerClient.Subscribe(topicName); _consumerClient.Subscribe(topicName);
} }
public void Listening(TimeSpan timeout) { public void Listening(TimeSpan timeout)
while (true) { {
while (true)
{
_consumerClient.Poll(timeout); _consumerClient.Poll(timeout);
} }
} }
public void Dispose() { public void Dispose()
{
_consumerClient.Dispose(); _consumerClient.Dispose();
} }
#region private methods #region private methods
private void InitKafkaClient() { private void InitKafkaClient()
{
var config = new Dictionary<string, object>{ var config = new Dictionary<string, object>{
{ "group.id", _groupId }, { "group.id", _groupId },
{ "bootstrap.servers", _bootstrapServers } { "bootstrap.servers", _bootstrapServers }
...@@ -60,8 +67,10 @@ namespace Cap.Consistency.Kafka ...@@ -60,8 +67,10 @@ namespace Cap.Consistency.Kafka
_consumerClient.OnMessage += ConsumerClient_OnMessage; _consumerClient.OnMessage += ConsumerClient_OnMessage;
} }
private void ConsumerClient_OnMessage(object sender, Message<Null, string> e) { private void ConsumerClient_OnMessage(object sender, Message<Null, string> e)
var message = new DeliverMessage { {
var message = new DeliverMessage
{
MessageKey = e.Topic, MessageKey = e.Topic,
Value = e.Value, Value = e.Value,
Body = Encoding.UTF8.GetBytes(e.Value) Body = Encoding.UTF8.GetBytes(e.Value)
......
using Cap.Consistency.Consumer; namespace DotNetCore.CAP.Kafka
namespace Cap.Consistency.Kafka
{ {
public class KafkaConsumerClientFactory : IConsumerClientFactory public class KafkaConsumerClientFactory : IConsumerClientFactory
{ {
public IConsumerClient Create(string groupId, string clientHostAddress) { public IConsumerClient Create(string groupId, string clientHostAddress)
{
return new KafkaConsumerClient(groupId, clientHostAddress); return new KafkaConsumerClient(groupId, clientHostAddress);
} }
} }
......
using Cap.Consistency.Abstractions; using DotNetCore.CAP.Abstractions;
namespace Cap.Consistency.Kafka namespace DotNetCore.CAP.Kafka
{ {
public class KafkaTopicAttribute : TopicAttribute public class KafkaTopicAttribute : TopicAttribute
{ {
......
using System; using System;
using System.Collections.Generic;
using System.Text;
using Microsoft.Extensions.Logging; using Microsoft.Extensions.Logging;
namespace Cap.Consistency.Kafka namespace DotNetCore.CAP.Kafka
{ {
internal static class LoggerExtensions internal static class LoggerExtensions
{ {
...@@ -20,7 +18,8 @@ namespace Cap.Consistency.Kafka ...@@ -20,7 +18,8 @@ namespace Cap.Consistency.Kafka
private static Action<ILogger, int, Exception> _jobCouldNotBeLoaded; private static Action<ILogger, int, Exception> _jobCouldNotBeLoaded;
private static Action<ILogger, string, Exception> _exceptionOccuredWhileExecutingJob; private static Action<ILogger, string, Exception> _exceptionOccuredWhileExecutingJob;
static LoggerExtensions() { static LoggerExtensions()
{
_collectingExpiredEntities = LoggerMessage.Define( _collectingExpiredEntities = LoggerMessage.Define(
LogLevel.Debug, LogLevel.Debug,
1, 1,
...@@ -73,45 +72,54 @@ namespace Cap.Consistency.Kafka ...@@ -73,45 +72,54 @@ namespace Cap.Consistency.Kafka
"Requeuing for another retry."); "Requeuing for another retry.");
} }
public static void CollectingExpiredEntities(this ILogger logger) { public static void CollectingExpiredEntities(this ILogger logger)
{
_collectingExpiredEntities(logger, null); _collectingExpiredEntities(logger, null);
} }
public static void Installing(this ILogger logger) { public static void Installing(this ILogger logger)
{
_installing(logger, null); _installing(logger, null);
} }
public static void InstallingError(this ILogger logger, Exception ex) { public static void InstallingError(this ILogger logger, Exception ex)
{
_installingError(logger, ex); _installingError(logger, ex);
} }
public static void InstallingSuccess(this ILogger logger) { public static void InstallingSuccess(this ILogger logger)
{
_installingSuccess(logger, null); _installingSuccess(logger, null);
} }
public static void JobFailed(this ILogger logger, Exception ex)
public static void JobFailed(this ILogger logger, Exception ex) { {
_jobFailed(logger, ex); _jobFailed(logger, ex);
} }
public static void JobFailedWillRetry(this ILogger logger, Exception ex) { public static void JobFailedWillRetry(this ILogger logger, Exception ex)
{
_jobFailedWillRetry(logger, ex); _jobFailedWillRetry(logger, ex);
} }
public static void JobRetrying(this ILogger logger, int retries) { public static void JobRetrying(this ILogger logger, int retries)
{
_jobRetrying(logger, retries, null); _jobRetrying(logger, retries, null);
} }
public static void JobExecuted(this ILogger logger, double seconds) { public static void JobExecuted(this ILogger logger, double seconds)
{
_jobExecuted(logger, seconds, null); _jobExecuted(logger, seconds, null);
} }
public static void JobCouldNotBeLoaded(this ILogger logger, int jobId, Exception ex) { public static void JobCouldNotBeLoaded(this ILogger logger, int jobId, Exception ex)
{
_jobCouldNotBeLoaded(logger, jobId, ex); _jobCouldNotBeLoaded(logger, jobId, ex);
} }
public static void ExceptionOccuredWhileExecutingJob(this ILogger logger, string jobId, Exception ex) { public static void ExceptionOccuredWhileExecutingJob(this ILogger logger, string jobId, Exception ex)
{
_exceptionOccuredWhileExecutingJob(logger, jobId, ex); _exceptionOccuredWhileExecutingJob(logger, jobId, ex);
} }
} }
} }
\ No newline at end of file
using Cap.Consistency.Consumer; using DotNetCore.CAP;
using Cap.Consistency.Job; using DotNetCore.CAP.Job;
using Cap.Consistency.Kafka; using DotNetCore.CAP.Kafka;
namespace Microsoft.Extensions.DependencyInjection namespace Microsoft.Extensions.DependencyInjection
{ {
public static class ConsistencyBuilderExtensions public static class ConsistencyBuilderExtensions
{ {
public static ConsistencyBuilder AddKafka(this ConsistencyBuilder builder) { public static CapBuilder AddKafka(this CapBuilder builder)
{
builder.Services.AddSingleton<IConsumerClientFactory, KafkaConsumerClientFactory>(); builder.Services.AddSingleton<IConsumerClientFactory, KafkaConsumerClientFactory>();
builder.Services.AddTransient<IJobProcessor, KafkaJobProcessor>(); builder.Services.AddTransient<IJobProcessor, KafkaJobProcessor>();
......
...@@ -10,7 +10,7 @@ ...@@ -10,7 +10,7 @@
</ItemGroup> </ItemGroup>
<ItemGroup> <ItemGroup>
<ProjectReference Include="..\Cap.Consistency\Cap.Consistency.csproj" /> <ProjectReference Include="..\DotNetCore.CAP\DotNetCore.CAP.csproj" />
</ItemGroup> </ItemGroup>
<ItemGroup> <ItemGroup>
......
using System; using System;
using System.Text; using System.Text;
using Cap.Consistency.Consumer; using DotNetCore.CAP.Infrastructure;
using Cap.Consistency.Infrastructure;
using RabbitMQ.Client; using RabbitMQ.Client;
using RabbitMQ.Client.Events; using RabbitMQ.Client.Events;
namespace Cap.Consistency.RabbitMQ namespace DotNetCore.CAP.RabbitMQ
{ {
public class RabbitMQConsumerClient : IConsumerClient public class RabbitMQConsumerClient : IConsumerClient
{ {
...@@ -22,14 +21,16 @@ namespace Cap.Consistency.RabbitMQ ...@@ -22,14 +21,16 @@ namespace Cap.Consistency.RabbitMQ
public event EventHandler<DeliverMessage> MessageReceieved; public event EventHandler<DeliverMessage> MessageReceieved;
public RabbitMQConsumerClient(string exchange, string hostName) { public RabbitMQConsumerClient(string exchange, string hostName)
{
_exchange = exchange; _exchange = exchange;
_hostName = hostName; _hostName = hostName;
InitClient(); InitClient();
} }
private void InitClient() { private void InitClient()
{
_connectionFactory = new ConnectionFactory { HostName = _hostName }; _connectionFactory = new ConnectionFactory { HostName = _hostName };
_connection = _connectionFactory.CreateConnection(); _connection = _connectionFactory.CreateConnection();
_channel = _connection.CreateModel(); _channel = _connection.CreateModel();
...@@ -37,7 +38,8 @@ namespace Cap.Consistency.RabbitMQ ...@@ -37,7 +38,8 @@ namespace Cap.Consistency.RabbitMQ
_queueName = _channel.QueueDeclare().QueueName; _queueName = _channel.QueueDeclare().QueueName;
} }
public void Listening(TimeSpan timeout) { public void Listening(TimeSpan timeout)
{
// Task.Delay(timeout).Wait(); // Task.Delay(timeout).Wait();
var consumer = new EventingBasicConsumer(_channel); var consumer = new EventingBasicConsumer(_channel);
...@@ -45,21 +47,26 @@ namespace Cap.Consistency.RabbitMQ ...@@ -45,21 +47,26 @@ namespace Cap.Consistency.RabbitMQ
_channel.BasicConsume(_queueName, true, consumer); _channel.BasicConsume(_queueName, true, consumer);
} }
public void Subscribe(string topic) { public void Subscribe(string topic)
{
_channel.QueueBind(_queueName, _exchange, topic); _channel.QueueBind(_queueName, _exchange, topic);
} }
public void Subscribe(string topic, int partition) { public void Subscribe(string topic, int partition)
{
_channel.QueueBind(_queueName, _exchange, topic); _channel.QueueBind(_queueName, _exchange, topic);
} }
public void Dispose() { public void Dispose()
{
_channel.Dispose(); _channel.Dispose();
_connection.Dispose(); _connection.Dispose();
} }
private void OnConsumerReceived(object sender, BasicDeliverEventArgs e) { private void OnConsumerReceived(object sender, BasicDeliverEventArgs e)
var message = new DeliverMessage { {
var message = new DeliverMessage
{
MessageKey = e.RoutingKey, MessageKey = e.RoutingKey,
Body = e.Body, Body = e.Body,
Value = Encoding.UTF8.GetString(e.Body) Value = Encoding.UTF8.GetString(e.Body)
......
using Cap.Consistency.Consumer; namespace DotNetCore.CAP.RabbitMQ
namespace Cap.Consistency.RabbitMQ
{ {
public class RabbitMQConsumerClientFactory : IConsumerClientFactory public class RabbitMQConsumerClientFactory : IConsumerClientFactory
{ {
public IConsumerClient Create(string groupId, string clientHostAddress) { public IConsumerClient Create(string groupId, string clientHostAddress)
{
return new RabbitMQConsumerClient(groupId, clientHostAddress); return new RabbitMQConsumerClient(groupId, clientHostAddress);
} }
} }
......
using System.Text; using System.Text;
using System.Threading.Tasks; using System.Threading.Tasks;
using Cap.Consistency.Infrastructure; using DotNetCore.CAP.Infrastructure;
using Microsoft.Extensions.Logging; using Microsoft.Extensions.Logging;
using Microsoft.Extensions.Options; using Microsoft.Extensions.Options;
using RabbitMQ.Client; using RabbitMQ.Client;
namespace Cap.Consistency.RabbitMQ namespace DotNetCore.CAP.RabbitMQ
{ {
public class RabbitMQProducerClient : IProducerClient public class RabbitMQProducerClient : ICapProducerService
{ {
private readonly ConsistencyOptions _options; private readonly ConsistencyOptions _options;
private readonly ILogger _logger; private readonly ILogger _logger;
public RabbitMQProducerClient(IOptions<ConsistencyOptions> options, ILoggerFactory loggerFactory) { public RabbitMQProducerClient(IOptions<ConsistencyOptions> options, ILoggerFactory loggerFactory)
{
_options = options.Value; _options = options.Value;
_logger = loggerFactory.CreateLogger(nameof(RabbitMQProducerClient)); _logger = loggerFactory.CreateLogger(nameof(RabbitMQProducerClient));
} }
public Task SendAsync(string topic, string content) { public Task SendAsync(string topic, string content)
{
var factory = new ConnectionFactory() { HostName = _options.BrokerUrlList }; var factory = new ConnectionFactory() { HostName = _options.BrokerUrlList };
using (var connection = factory.CreateConnection()) using (var connection = factory.CreateConnection())
using (var channel = connection.CreateModel()) { using (var channel = connection.CreateModel())
{
channel.ExchangeDeclare(exchange: "topic_logs", channel.ExchangeDeclare(exchange: "topic_logs",
type: "topic"); type: "topic");
......
using System; using DotNetCore.CAP.Abstractions;
using System.Collections.Generic;
using System.Text;
using Cap.Consistency.Abstractions;
namespace Cap.Consistency.RabbitMQ namespace DotNetCore.CAP.RabbitMQ
{ {
public class RabbitMQTopicAttribute : TopicAttribute public class RabbitMQTopicAttribute : TopicAttribute
{ {
public RabbitMQTopicAttribute(string routingKey) : base(routingKey)
public RabbitMQTopicAttribute(string routingKey) : base(routingKey) { {
} }
} }
} }
\ No newline at end of file
using System; using System;
using System.Collections.Generic; using DotNetCore.CAP.Infrastructure;
using System.Text;
using System.Threading.Tasks;
using Cap.Consistency.Infrastructure;
namespace Cap.Consistency.Abstractions namespace DotNetCore.CAP.Abstractions
{ {
public class ConsumerContext public class ConsumerContext
{ {
public ConsumerContext(ConsumerExecutorDescriptor descriptor, DeliverMessage message) { public ConsumerContext(ConsumerExecutorDescriptor descriptor, DeliverMessage message)
{
ConsumerDescriptor = descriptor ?? throw new ArgumentNullException(nameof(descriptor)); ConsumerDescriptor = descriptor ?? throw new ArgumentNullException(nameof(descriptor));
DeliverMessage = message ?? throw new ArgumentNullException(nameof(message)); DeliverMessage = message ?? throw new ArgumentNullException(nameof(message));
} }
...@@ -18,4 +15,4 @@ namespace Cap.Consistency.Abstractions ...@@ -18,4 +15,4 @@ namespace Cap.Consistency.Abstractions
public DeliverMessage DeliverMessage { get; set; } public DeliverMessage DeliverMessage { get; set; }
} }
} }
\ No newline at end of file
using System; using System.Reflection;
using System.Collections.Generic;
using System.Reflection;
using System.Text;
namespace Cap.Consistency.Abstractions namespace DotNetCore.CAP.Abstractions
{ {
public class ConsumerExecutorDescriptor public class ConsumerExecutorDescriptor
{ {
...@@ -13,4 +10,4 @@ namespace Cap.Consistency.Abstractions ...@@ -13,4 +10,4 @@ namespace Cap.Consistency.Abstractions
public TopicAttribute Attribute { get; set; } public TopicAttribute Attribute { get; set; }
} }
} }
\ No newline at end of file
using System; using System;
using System.Collections.Generic;
using System.Text;
namespace Cap.Consistency.Abstractions namespace DotNetCore.CAP.Abstractions
{ {
public class ConsumerInvokerContext public class ConsumerInvokerContext
{ {
public ConsumerInvokerContext(ConsumerContext consumerContext) { public ConsumerInvokerContext(ConsumerContext consumerContext)
ConsumerContext = consumerContext ?? {
ConsumerContext = consumerContext ??
throw new ArgumentNullException(nameof(consumerContext)); throw new ArgumentNullException(nameof(consumerContext));
} }
public ConsumerContext ConsumerContext { get; set; } public ConsumerContext ConsumerContext { get; set; }
public IConsumerInvoker Result { get; set; } public IConsumerInvoker Result { get; set; }
} }
} }
\ No newline at end of file
using System; using System.Threading.Tasks;
using System.Collections.Generic;
using System.Text;
using System.Threading.Tasks;
namespace Cap.Consistency.Abstractions namespace DotNetCore.CAP.Abstractions
{ {
public interface IConsumerInvoker public interface IConsumerInvoker
{ {
Task InvokeAsync(); Task InvokeAsync();
} }
} }
\ No newline at end of file
using System; using System.Threading.Tasks;
using System.Collections.Generic;
using System.Text;
using System.Threading.Tasks;
namespace Cap.Consistency.Abstractions.ModelBinding namespace DotNetCore.CAP.Abstractions.ModelBinding
{ {
public interface IModelBinder public interface IModelBinder
{ {
Task BindModelAsync(ModelBindingContext bindingContext); Task BindModelAsync(ModelBindingContext bindingContext);
} }
} }
\ No newline at end of file
using System; using System;
using System.Collections.Generic;
using System.Text;
using Microsoft.Extensions.Primitives; using Microsoft.Extensions.Primitives;
namespace Cap.Consistency.Abstractions.ModelBinding namespace DotNetCore.CAP.Abstractions.ModelBinding
{ {
public class ModelBindingContext public class ModelBindingContext
{ {
...@@ -17,12 +15,14 @@ namespace Cap.Consistency.Abstractions.ModelBinding ...@@ -17,12 +15,14 @@ namespace Cap.Consistency.Abstractions.ModelBinding
public object Result { get; set; } public object Result { get; set; }
public static ModelBindingContext CreateBindingContext(string values, string modelName, Type modelType) { public static ModelBindingContext CreateBindingContext(string values, string modelName, Type modelType)
return new ModelBindingContext() { {
return new ModelBindingContext()
{
ModelName = modelName, ModelName = modelName,
ModelType = modelType, ModelType = modelType,
Values = values Values = values
}; };
} }
} }
} }
\ No newline at end of file
using System; using System;
using System.Collections.Generic;
using System.Text;
namespace Cap.Consistency.Abstractions namespace DotNetCore.CAP.Abstractions
{ {
[AttributeUsage(AttributeTargets.Method | AttributeTargets.Class, Inherited = true, AllowMultiple = true)] [AttributeUsage(AttributeTargets.Method | AttributeTargets.Class, Inherited = true, AllowMultiple = true)]
public abstract class TopicAttribute : Attribute public abstract class TopicAttribute : Attribute
{ {
readonly string _name; private readonly string _name;
public TopicAttribute(string topicName) { public TopicAttribute(string topicName)
{
this._name = topicName; this._name = topicName;
} }
public string Name { public string Name
{
get { return _name; } get { return _name; }
} }
...@@ -22,4 +21,4 @@ namespace Cap.Consistency.Abstractions ...@@ -22,4 +21,4 @@ namespace Cap.Consistency.Abstractions
public bool IsOneWay { get; set; } public bool IsOneWay { get; set; }
} }
} }
\ No newline at end of file
using System; using System;
using Cap.Consistency; using DotNetCore.CAP;
using Microsoft.Extensions.DependencyInjection; using Microsoft.Extensions.DependencyInjection;
// ReSharper disable once CheckNamespace
namespace Microsoft.AspNetCore.Builder namespace Microsoft.AspNetCore.Builder
{ {
/// <summary> /// <summary>
/// Consistence extensions for <see cref="IApplicationBuilder"/> /// Consistence extensions for <see cref="IApplicationBuilder"/>
/// </summary> /// </summary>
public static class BuilderExtensions public static class AppBuilderExtensions
{ {
///<summary> ///<summary>
/// Enables Consistence for the current application /// Enables Consistence for the current application
/// </summary> /// </summary>
/// <param name="app">The <see cref="IApplicationBuilder"/> instance this method extends.</param> /// <param name="app">The <see cref="IApplicationBuilder"/> instance this method extends.</param>
/// <returns>The <see cref="IApplicationBuilder"/> instance this method extends.</returns> /// <returns>The <see cref="IApplicationBuilder"/> instance this method extends.</returns>
public static IApplicationBuilder UseConsistency(this IApplicationBuilder app) { public static IApplicationBuilder UseConsistency(this IApplicationBuilder app)
if (app == null) { {
if (app == null)
{
throw new ArgumentNullException(nameof(app)); throw new ArgumentNullException(nameof(app));
} }
var marker = app.ApplicationServices.GetService<ConsistencyMarkerService>(); var marker = app.ApplicationServices.GetService<CapMarkerService>();
if (marker == null) { if (marker == null)
{
throw new InvalidOperationException("Add Consistency must be called on the service collection."); throw new InvalidOperationException("Add Consistency must be called on the service collection.");
} }
......
using System; using System;
using Cap.Consistency; using DotNetCore.CAP;
using Cap.Consistency.Job; using DotNetCore.CAP.Job;
namespace Microsoft.Extensions.DependencyInjection namespace Microsoft.Extensions.DependencyInjection
{ {
/// <summary> /// <summary>
/// Used to verify Consistency service was called on a ServiceCollection /// Used to verify Consistency service was called on a ServiceCollection
/// </summary> /// </summary>
public class ConsistencyMarkerService { } public class CapMarkerService { }
public class ConsistencyBuilder public class CapBuilder
{ {
public ConsistencyBuilder(IServiceCollection services) { public CapBuilder(IServiceCollection services)
{
Services = services; Services = services;
} }
public IServiceCollection Services { get; private set; } public IServiceCollection Services { get; private set; }
private ConsistencyBuilder AddScoped(Type serviceType, Type concreteType) { private CapBuilder AddScoped(Type serviceType, Type concreteType)
{
Services.AddScoped(serviceType, concreteType); Services.AddScoped(serviceType, concreteType);
return this; return this;
} }
private ConsistencyBuilder AddSingleton<TService, TImplementation>() private CapBuilder AddSingleton<TService, TImplementation>()
where TService : class where TService : class
where TImplementation : class, TService { where TImplementation : class, TService
{
Services.AddSingleton<TService, TImplementation>(); Services.AddSingleton<TService, TImplementation>();
return this; return this;
} }
/// <summary> /// <summary>
/// Adds an <see cref="IConsistencyMessageStore"/> . /// Adds an <see cref="ICapMessageStore"/> .
/// </summary> /// </summary>
/// <typeparam name="T">The type for the <see cref="IConsistencyMessageStore"/> to add. </typeparam> /// <typeparam name="T">The type for the <see cref="ICapMessageStore"/> to add. </typeparam>
/// <returns>The current <see cref="ConsistencyBuilder"/> instance.</returns> /// <returns>The current <see cref="CapBuilder"/> instance.</returns>
public virtual ConsistencyBuilder AddMessageStore<T>() public virtual CapBuilder AddMessageStore<T>()
where T : class, IConsistencyMessageStore { where T : class, ICapMessageStore
{
return AddScoped(typeof(IConsistencyMessageStore), typeof(T)); return AddScoped(typeof(ICapMessageStore), typeof(T));
} }
public virtual ConsistencyBuilder AddJobs<T>() public virtual CapBuilder AddJobs<T>()
where T : class, IJob { where T : class, IJob
{
return AddSingleton<IJob, T>(); return AddSingleton<IJob, T>();
} }
public virtual ConsistencyBuilder AddProducerClient<T>() public virtual CapBuilder AddProducerClient<T>()
where T:class, IProducerClient { where T : class, ICapProducerService
{
return AddScoped(typeof(IProducerClient), typeof(T)); return AddScoped(typeof(ICapProducerService), typeof(T));
} }
} }
} }
\ No newline at end of file
using System; using System;
using System.Collections.Generic; using System.Collections.Generic;
using System.Reflection; using System.Reflection;
using Cap.Consistency; using DotNetCore.CAP;
using Cap.Consistency.Abstractions.ModelBinding; using DotNetCore.CAP.Abstractions.ModelBinding;
using Cap.Consistency.Consumer; using DotNetCore.CAP.Infrastructure;
using Cap.Consistency.Infrastructure; using DotNetCore.CAP.Internal;
using Cap.Consistency.Internal; using DotNetCore.CAP.Job;
using Cap.Consistency.Job;
using Microsoft.Extensions.DependencyInjection.Extensions; using Microsoft.Extensions.DependencyInjection.Extensions;
namespace Microsoft.Extensions.DependencyInjection namespace Microsoft.Extensions.DependencyInjection
...@@ -20,11 +19,12 @@ namespace Microsoft.Extensions.DependencyInjection ...@@ -20,11 +19,12 @@ namespace Microsoft.Extensions.DependencyInjection
/// Adds and configures the consistence services for the consitence. /// Adds and configures the consistence services for the consitence.
/// </summary> /// </summary>
/// <param name="services">The services available in the application.</param> /// <param name="services">The services available in the application.</param>
/// <returns>An <see cref="ConsistencyBuilder"/> for application services.</returns> /// <returns>An <see cref="CapBuilder"/> for application services.</returns>
public static ConsistencyBuilder AddConsistency(this IServiceCollection services) { public static CapBuilder AddConsistency(this IServiceCollection services)
{
services.AddConsistency(x => new ConsistencyOptions()); services.AddConsistency(x => new ConsistencyOptions());
return new ConsistencyBuilder(services); return new CapBuilder(services);
} }
/// <summary> /// <summary>
...@@ -32,12 +32,12 @@ namespace Microsoft.Extensions.DependencyInjection ...@@ -32,12 +32,12 @@ namespace Microsoft.Extensions.DependencyInjection
/// </summary> /// </summary>
/// <param name="services">The services available in the application.</param> /// <param name="services">The services available in the application.</param>
/// <param name="setupAction">An action to configure the <see cref="ConsistencyOptions"/>.</param> /// <param name="setupAction">An action to configure the <see cref="ConsistencyOptions"/>.</param>
/// <returns>An <see cref="ConsistencyBuilder"/> for application services.</returns> /// <returns>An <see cref="CapBuilder"/> for application services.</returns>
public static ConsistencyBuilder AddConsistency( public static CapBuilder AddConsistency(
this IServiceCollection services, this IServiceCollection services,
Action<ConsistencyOptions> setupAction) { Action<ConsistencyOptions> setupAction)
{
services.TryAddSingleton<ConsistencyMarkerService>(); services.TryAddSingleton<CapMarkerService>();
services.Configure(setupAction); services.Configure(setupAction);
AddConsumerServices(services); AddConsumerServices(services);
...@@ -55,27 +55,32 @@ namespace Microsoft.Extensions.DependencyInjection ...@@ -55,27 +55,32 @@ namespace Microsoft.Extensions.DependencyInjection
services.TryAddSingleton<IJob, CapJob>(); services.TryAddSingleton<IJob, CapJob>();
services.TryAddTransient<DefaultCronJobRegistry>(); services.TryAddTransient<DefaultCronJobRegistry>();
services.TryAddScoped<IProducerClient, DefaultProducerClient>(); services.TryAddScoped<ICapProducerService, DefaultProducerService>();
return new ConsistencyBuilder(services); return new CapBuilder(services);
} }
private static void AddConsumerServices(IServiceCollection services) { private static void AddConsumerServices(IServiceCollection services)
{
var consumerListenerServices = new Dictionary<Type, Type>(); var consumerListenerServices = new Dictionary<Type, Type>();
foreach (var rejectedServices in services) { foreach (var rejectedServices in services)
{
if (rejectedServices.ImplementationType != null if (rejectedServices.ImplementationType != null
&& typeof(IConsumerService).IsAssignableFrom(rejectedServices.ImplementationType)) && typeof(IConsumerService).IsAssignableFrom(rejectedServices.ImplementationType))
consumerListenerServices.Add(typeof(IConsumerService), rejectedServices.ImplementationType); consumerListenerServices.Add(typeof(IConsumerService), rejectedServices.ImplementationType);
} }
foreach (var service in consumerListenerServices) { foreach (var service in consumerListenerServices)
{
services.AddSingleton(service.Key, service.Value); services.AddSingleton(service.Key, service.Value);
} }
var types = Assembly.GetEntryAssembly().ExportedTypes; var types = Assembly.GetEntryAssembly().ExportedTypes;
foreach (var type in types) { foreach (var type in types)
if (typeof(IConsumerService).IsAssignableFrom(type)) { {
if (typeof(IConsumerService).IsAssignableFrom(type))
{
services.AddSingleton(typeof(IConsumerService), type); services.AddSingleton(typeof(IConsumerService), type);
} }
} }
......
<Project Sdk="Microsoft.NET.Sdk"> <Project Sdk="Microsoft.NET.Sdk">
<PropertyGroup> <PropertyGroup>
<PackageId>Cap.Consistency</PackageId> <PackageId>DotNetCore.CAP</PackageId>
<TargetFramework>netstandard1.6</TargetFramework> <TargetFramework>netstandard1.6</TargetFramework>
<NetStandardImplicitPackageVersion>1.6.1</NetStandardImplicitPackageVersion> <NetStandardImplicitPackageVersion>1.6.1</NetStandardImplicitPackageVersion>
<PackageTargetFallback>$(PackageTargetFallback);dnxcore50</PackageTargetFallback> <PackageTargetFallback>$(PackageTargetFallback);dnxcore50</PackageTargetFallback>
......
using System; using System;
using System.Linq;
using System.Collections.Generic; using System.Collections.Generic;
using System.Threading; using System.Threading;
using System.Threading.Tasks; using System.Threading.Tasks;
using Cap.Consistency.Infrastructure; using DotNetCore.CAP.Infrastructure;
using Microsoft.AspNetCore.Hosting; using Microsoft.AspNetCore.Hosting;
using Microsoft.Extensions.DependencyInjection; using Microsoft.Extensions.DependencyInjection;
using Microsoft.Extensions.Options; using Microsoft.Extensions.Options;
namespace Cap.Consistency namespace DotNetCore.CAP
{ {
public class DefaultBootstrapper : IBootstrapper public class DefaultBootstrapper : IBootstrapper
{ {
...@@ -19,39 +18,44 @@ namespace Cap.Consistency ...@@ -19,39 +18,44 @@ namespace Cap.Consistency
public DefaultBootstrapper( public DefaultBootstrapper(
IOptions<ConsistencyOptions> options, IOptions<ConsistencyOptions> options,
IConsistencyMessageStore storage, ICapMessageStore storage,
IApplicationLifetime appLifetime, IApplicationLifetime appLifetime,
IServiceProvider provider) { IServiceProvider provider)
{
Options = options.Value; Options = options.Value;
Storage = storage; Storage = storage;
_appLifetime = appLifetime; _appLifetime = appLifetime;
Provider = provider; Provider = provider;
Servers = Provider.GetServices<IProcessingServer>(); Servers = Provider.GetServices<IProcessingServer>();
_cts = new CancellationTokenSource(); _cts = new CancellationTokenSource();
_ctsRegistration = appLifetime.ApplicationStopping.Register(() => { _ctsRegistration = appLifetime.ApplicationStopping.Register(() =>
{
_cts.Cancel(); _cts.Cancel();
try { try
{
_bootstrappingTask?.Wait(); _bootstrappingTask?.Wait();
} }
catch (OperationCanceledException) { catch (OperationCanceledException)
{
} }
}); });
} }
protected ConsistencyOptions Options { get; } protected ConsistencyOptions Options { get; }
protected IConsistencyMessageStore Storage { get; } protected ICapMessageStore Storage { get; }
protected IEnumerable<IProcessingServer> Servers { get; } protected IEnumerable<IProcessingServer> Servers { get; }
public IServiceProvider Provider { get; private set; } public IServiceProvider Provider { get; private set; }
public Task BootstrapAsync() { public Task BootstrapAsync()
{
return (_bootstrappingTask = BootstrapTaskAsync()); return (_bootstrappingTask = BootstrapTaskAsync());
} }
private async Task BootstrapTaskAsync() { private async Task BootstrapTaskAsync()
{
if (_cts.IsCancellationRequested) return; if (_cts.IsCancellationRequested) return;
if (_cts.IsCancellationRequested) return; if (_cts.IsCancellationRequested) return;
...@@ -60,11 +64,14 @@ namespace Cap.Consistency ...@@ -60,11 +64,14 @@ namespace Cap.Consistency
if (_cts.IsCancellationRequested) return; if (_cts.IsCancellationRequested) return;
foreach (var item in Servers) { foreach (var item in Servers)
try { {
try
{
item.Start(); item.Start();
} }
catch (Exception) { catch (Exception)
{
} }
} }
...@@ -72,9 +79,12 @@ namespace Cap.Consistency ...@@ -72,9 +79,12 @@ namespace Cap.Consistency
_cts.Dispose(); _cts.Dispose();
} }
public virtual Task BootstrapCoreAsync() { public virtual Task BootstrapCoreAsync()
_appLifetime.ApplicationStopping.Register(() => { {
foreach (var item in Servers) { _appLifetime.ApplicationStopping.Register(() =>
{
foreach (var item in Servers)
{
item.Dispose(); item.Dispose();
} }
}); });
......
using System.Threading.Tasks; using System.Threading.Tasks;
namespace Cap.Consistency namespace DotNetCore.CAP
{ {
/// <summary> /// <summary>
/// Represents bootstrapping logic. For example, adding initial state to the storage or querying certain entities. /// Represents bootstrapping logic. For example, adding initial state to the storage or querying certain entities.
......
using System; using System.Threading;
using System.Threading;
using System.Threading.Tasks; using System.Threading.Tasks;
using Cap.Consistency.Infrastructure; using DotNetCore.CAP.Infrastructure;
namespace Cap.Consistency namespace DotNetCore.CAP
{ {
/// <summary> /// <summary>
/// Provides an abstraction for a store which manages consistent message. /// Provides an abstraction for a store which manages consistent message.
/// </summary> /// </summary>
/// <typeparam name="ConsistencyMessage"></typeparam> /// <typeparam name="ConsistencyMessage"></typeparam>
public interface IConsistencyMessageStore public interface ICapMessageStore
{ {
/// <summary> /// <summary>
/// Finds and returns a message, if any, who has the specified <paramref name="messageId"/>. /// Finds and returns a message, if any, who has the specified <paramref name="messageId"/>.
...@@ -20,7 +19,6 @@ namespace Cap.Consistency ...@@ -20,7 +19,6 @@ namespace Cap.Consistency
/// The <see cref="Task"/> that represents the asynchronous operation, containing the message matching the specified <paramref name="messageId"/> if it exists. /// The <see cref="Task"/> that represents the asynchronous operation, containing the message matching the specified <paramref name="messageId"/> if it exists.
/// </returns> /// </returns>
Task<ConsistencyMessage> FindByIdAsync(string messageId, CancellationToken cancellationToken); Task<ConsistencyMessage> FindByIdAsync(string messageId, CancellationToken cancellationToken);
/// <summary> /// <summary>
/// Creates a new message in a store as an asynchronous operation. /// Creates a new message in a store as an asynchronous operation.
...@@ -56,6 +54,6 @@ namespace Cap.Consistency ...@@ -56,6 +54,6 @@ namespace Cap.Consistency
Task<ConsistencyMessage> GetFirstEnqueuedMessageAsync(CancellationToken cancellationToken); Task<ConsistencyMessage> GetFirstEnqueuedMessageAsync(CancellationToken cancellationToken);
// void ChangeState(ConsistencyMessage message, MessageStatus status); // void ChangeState(ConsistencyMessage message, MessageStatus status);
} }
} }
\ No newline at end of file
using System; using System;
using System.Threading; using System.Threading;
using System.Threading.Tasks; using System.Threading.Tasks;
using Cap.Consistency.Infrastructure; using DotNetCore.CAP.Infrastructure;
using Microsoft.Extensions.Logging; using Microsoft.Extensions.Logging;
namespace Cap.Consistency namespace DotNetCore.CAP
{ {
public class DefaultProducerClient : IProducerClient public class DefaultProducerService : ICapProducerService
{ {
private readonly IConsistencyMessageStore _store; private readonly ICapMessageStore _store;
private readonly ILogger _logger; private readonly ILogger _logger;
private readonly CancellationTokenSource _cts; private readonly CancellationTokenSource _cts;
public DefaultProducerClient( public DefaultProducerService(
IConsistencyMessageStore store, ICapMessageStore store,
ILogger<DefaultProducerClient> logger) { ILogger<DefaultProducerService> logger)
{
_store = store; _store = store;
_logger = logger; _logger = logger;
_cts = new CancellationTokenSource(); _cts = new CancellationTokenSource();
} }
public Task SendAsync(string topic, string content) { public Task SendAsync(string topic, string content)
{
if (topic == null) throw new ArgumentNullException(nameof(topic)); if (topic == null) throw new ArgumentNullException(nameof(topic));
if (content == null) throw new ArgumentNullException(nameof(content)); if (content == null) throw new ArgumentNullException(nameof(content));
return StoreMessage(topic, content); return StoreMessage(topic, content);
} }
public Task SendAsync<T>(string topic, T obj) { public Task SendAsync<T>(string topic, T obj)
{
if (topic == null) throw new ArgumentNullException(nameof(topic)); if (topic == null) throw new ArgumentNullException(nameof(topic));
var content = Helper.ToJson(obj); var content = Helper.ToJson(obj);
...@@ -38,9 +40,10 @@ namespace Cap.Consistency ...@@ -38,9 +40,10 @@ namespace Cap.Consistency
return StoreMessage(topic, content); return StoreMessage(topic, content);
} }
private async Task StoreMessage(string topic, string content) { private async Task StoreMessage(string topic, string content)
{
var message = new ConsistencyMessage { var message = new ConsistencyMessage
{
Topic = topic, Topic = topic,
Payload = content Payload = content
}; };
...@@ -49,9 +52,10 @@ namespace Cap.Consistency ...@@ -49,9 +52,10 @@ namespace Cap.Consistency
WaitHandleEx.PulseEvent.Set(); WaitHandleEx.PulseEvent.Set();
if (_logger.IsEnabled(LogLevel.Debug)) { if (_logger.IsEnabled(LogLevel.Debug))
{
_logger.LogDebug("Enqueuing a topic to be store. topic:{topic}, content:{content}", topic, content); _logger.LogDebug("Enqueuing a topic to be store. topic:{topic}, content:{content}", topic, content);
} }
} }
} }
} }
\ No newline at end of file
using System.Threading.Tasks;
namespace DotNetCore.CAP
{
public interface ICapProducerService
{
Task SendAsync(string topic, string content);
}
}
\ No newline at end of file
using System; using System;
using System.Collections.Generic; using System.Collections.Generic;
using System.Text; using System.Text;
using Cap.Consistency.Infrastructure; using DotNetCore.CAP.Infrastructure;
namespace Cap.Consistency.Consumer namespace DotNetCore.CAP
{ {
public interface IConsumerClient : IDisposable public interface IConsumerClient : IDisposable
{ {
......
...@@ -3,7 +3,7 @@ using System.Collections.Generic; ...@@ -3,7 +3,7 @@ using System.Collections.Generic;
using System.Text; using System.Text;
using System.Threading.Tasks; using System.Threading.Tasks;
namespace Cap.Consistency.Consumer namespace DotNetCore.CAP
{ {
public interface IConsumerClientFactory public interface IConsumerClientFactory
{ {
......
...@@ -3,13 +3,13 @@ using System.Linq; ...@@ -3,13 +3,13 @@ using System.Linq;
using System.Text; using System.Text;
using System.Threading; using System.Threading;
using System.Threading.Tasks; using System.Threading.Tasks;
using Cap.Consistency.Abstractions; using DotNetCore.CAP.Abstractions;
using Cap.Consistency.Infrastructure; using DotNetCore.CAP.Infrastructure;
using Cap.Consistency.Internal; using DotNetCore.CAP.Internal;
using Microsoft.Extensions.Logging; using Microsoft.Extensions.Logging;
using Microsoft.Extensions.Options; using Microsoft.Extensions.Options;
namespace Cap.Consistency.Consumer namespace DotNetCore.CAP
{ {
public class ConsumerHandler : IConsumerHandler, IDisposable public class ConsumerHandler : IConsumerHandler, IDisposable
{ {
...@@ -21,7 +21,7 @@ namespace Cap.Consistency.Consumer ...@@ -21,7 +21,7 @@ namespace Cap.Consistency.Consumer
private readonly MethodMatcherCache _selector; private readonly MethodMatcherCache _selector;
private readonly ConsistencyOptions _options; private readonly ConsistencyOptions _options;
private readonly IConsistencyMessageStore _messageStore; private readonly ICapMessageStore _messageStore;
private readonly CancellationTokenSource _cts; private readonly CancellationTokenSource _cts;
public event EventHandler<ConsistencyMessage> MessageReceieved; public event EventHandler<ConsistencyMessage> MessageReceieved;
...@@ -35,7 +35,7 @@ namespace Cap.Consistency.Consumer ...@@ -35,7 +35,7 @@ namespace Cap.Consistency.Consumer
IConsumerInvokerFactory consumerInvokerFactory, IConsumerInvokerFactory consumerInvokerFactory,
IConsumerClientFactory consumerClientFactory, IConsumerClientFactory consumerClientFactory,
ILoggerFactory loggerFactory, ILoggerFactory loggerFactory,
IConsistencyMessageStore messageStore, ICapMessageStore messageStore,
MethodMatcherCache selector, MethodMatcherCache selector,
IOptions<ConsistencyOptions> options) { IOptions<ConsistencyOptions> options) {
_selector = selector; _selector = selector;
......
namespace Cap.Consistency.Consumer namespace DotNetCore.CAP
{ {
public interface IConsumerHandler : IProcessingServer public interface IConsumerHandler : IProcessingServer
{ {
} }
} }
\ No newline at end of file
using System; namespace DotNetCore.CAP
using System.Collections.Generic;
using System.Text;
namespace Cap.Consistency.Consumer
{ {
public interface IConsumerService public interface IConsumerService
{ {
} }
} }
\ No newline at end of file
using System; using System;
using System.Collections.Generic;
using System.Text;
using System.Threading.Tasks;
namespace Cap.Consistency namespace DotNetCore.CAP
{ {
public interface IProcessingServer : IDisposable public interface IProcessingServer : IDisposable
{ {
void Start(); void Start();
} }
} }
\ No newline at end of file
using System; using System;
namespace Cap.Consistency.Infrastructure namespace DotNetCore.CAP.Infrastructure
{ {
/// <summary> /// <summary>
/// The default implementation of <see cref="ConsistencyMessage{TKey}"/> which uses a string as a primary key. /// The default implementation of <see cref="ConsistencyMessage{TKey}"/> which uses a string as a primary key.
...@@ -13,7 +13,8 @@ namespace Cap.Consistency.Infrastructure ...@@ -13,7 +13,8 @@ namespace Cap.Consistency.Infrastructure
/// <remarks> /// <remarks>
/// The Id property is initialized to from a new GUID string value. /// The Id property is initialized to from a new GUID string value.
/// </remarks> /// </remarks>
public ConsistencyMessage() { public ConsistencyMessage()
{
Id = Guid.NewGuid().ToString(); Id = Guid.NewGuid().ToString();
SendTime = DateTime.Now; SendTime = DateTime.Now;
UpdateTime = SendTime; UpdateTime = SendTime;
......
using Cap.Consistency.Job; using DotNetCore.CAP.Job;
namespace Cap.Consistency.Infrastructure namespace DotNetCore.CAP.Infrastructure
{ {
/// <summary> /// <summary>
/// Represents all the options you can use to configure the system. /// Represents all the options you can use to configure the system.
......
using System; namespace DotNetCore.CAP.Infrastructure
using System.Collections.Generic;
using System.Text;
namespace Cap.Consistency.Infrastructure
{ {
public class DeliverMessage public class DeliverMessage
{ {
...@@ -14,9 +10,8 @@ namespace Cap.Consistency.Infrastructure ...@@ -14,9 +10,8 @@ namespace Cap.Consistency.Infrastructure
/// </summary> /// </summary>
public string MessageKey { get; set; } public string MessageKey { get; set; }
public byte[] Body { get; set; } public byte[] Body { get; set; }
public string Value { get; set; } public string Value { get; set; }
} }
} }
\ No newline at end of file
using System; using System;
using System.Collections.Generic;
using System.Text;
using Newtonsoft.Json; using Newtonsoft.Json;
namespace Cap.Consistency.Infrastructure namespace DotNetCore.CAP.Infrastructure
{ {
internal static class Helper internal 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.Utc);
private static JsonSerializerSettings SerializerSettings; private static JsonSerializerSettings SerializerSettings;
public static void SetSerializerSettings(JsonSerializerSettings setting) { public static void SetSerializerSettings(JsonSerializerSettings setting)
{
SerializerSettings = setting; SerializerSettings = setting;
} }
public static string ToJson(object value) { public static string ToJson(object value)
{
return value != null return value != null
? JsonConvert.SerializeObject(value, SerializerSettings) ? JsonConvert.SerializeObject(value, SerializerSettings)
: null; : null;
} }
public static T FromJson<T>(string value) { public static T FromJson<T>(string value)
{
return value != null return value != null
? JsonConvert.DeserializeObject<T>(value, SerializerSettings) ? JsonConvert.DeserializeObject<T>(value, SerializerSettings)
: default(T); : default(T);
} }
public static object FromJson(string value, Type type) { public static object FromJson(string value, Type type)
{
if (type == null) throw new ArgumentNullException(nameof(type)); if (type == null) throw new ArgumentNullException(nameof(type));
return value != null return value != null
...@@ -34,13 +36,15 @@ namespace Cap.Consistency.Infrastructure ...@@ -34,13 +36,15 @@ namespace Cap.Consistency.Infrastructure
: null; : null;
} }
public static long ToTimestamp(DateTime value) { public static long ToTimestamp(DateTime value)
{
var elapsedTime = value - Epoch; var elapsedTime = value - Epoch;
return (long)elapsedTime.TotalSeconds; return (long)elapsedTime.TotalSeconds;
} }
public static DateTime FromTimestamp(long value) { public static DateTime FromTimestamp(long value)
{
return Epoch.AddSeconds(value); return Epoch.AddSeconds(value);
} }
} }
} }
\ No newline at end of file
using System; using System.Collections.Generic;
using System.Collections.Generic; using DotNetCore.CAP.Abstractions;
using System.Text;
using Cap.Consistency.Abstractions;
namespace Cap.Consistency.Infrastructure namespace DotNetCore.CAP.Infrastructure
{ {
public interface IConsumerExcutorSelector public interface IConsumerExcutorSelector
{ {
...@@ -11,4 +9,4 @@ namespace Cap.Consistency.Infrastructure ...@@ -11,4 +9,4 @@ namespace Cap.Consistency.Infrastructure
ConsumerExecutorDescriptor SelectBestCandidate(string key, IReadOnlyList<ConsumerExecutorDescriptor> executeDescriptor); ConsumerExecutorDescriptor SelectBestCandidate(string key, IReadOnlyList<ConsumerExecutorDescriptor> executeDescriptor);
} }
} }
\ No newline at end of file
using System; using DotNetCore.CAP.Abstractions;
using System.Collections.Generic;
using System.Text;
using Cap.Consistency.Abstractions;
namespace Cap.Consistency.Infrastructure namespace DotNetCore.CAP.Infrastructure
{ {
public interface IConsumerInvokerFactory public interface IConsumerInvokerFactory
{ {
IConsumerInvoker CreateInvoker(ConsumerContext actionContext); IConsumerInvoker CreateInvoker(ConsumerContext actionContext);
} }
} }
\ No newline at end of file
using System; using System;
using System.Collections.Generic;
using System.Text;
using System.Threading; using System.Threading;
using System.Threading.Tasks; using System.Threading.Tasks;
namespace Cap.Consistency.Infrastructure namespace DotNetCore.CAP.Infrastructure
{ {
public static class WaitHandleEx public static class WaitHandleEx
{ {
public static readonly AutoResetEvent PulseEvent = new AutoResetEvent(true); public static readonly AutoResetEvent PulseEvent = new AutoResetEvent(true);
public static Task WaitAnyAsync(WaitHandle handle1, WaitHandle handle2, TimeSpan timeout) { public static Task WaitAnyAsync(WaitHandle handle1, WaitHandle handle2, TimeSpan timeout)
{
var t1 = handle1.WaitOneAsync(timeout); var t1 = handle1.WaitOneAsync(timeout);
var t2 = handle2.WaitOneAsync(timeout); var t2 = handle2.WaitOneAsync(timeout);
return Task.WhenAny(t1, t2); return Task.WhenAny(t1, t2);
} }
public static async Task<bool> WaitOneAsync(this WaitHandle handle, TimeSpan timeout) { public static async Task<bool> WaitOneAsync(this WaitHandle handle, TimeSpan timeout)
{
RegisteredWaitHandle registeredHandle = null; RegisteredWaitHandle registeredHandle = null;
try { try
{
var tcs = new TaskCompletionSource<bool>(); var tcs = new TaskCompletionSource<bool>();
registeredHandle = ThreadPool.RegisterWaitForSingleObject( registeredHandle = ThreadPool.RegisterWaitForSingleObject(
handle, handle,
...@@ -28,11 +29,13 @@ namespace Cap.Consistency.Infrastructure ...@@ -28,11 +29,13 @@ namespace Cap.Consistency.Infrastructure
true); true);
return await tcs.Task; return await tcs.Task;
} }
finally { finally
if (registeredHandle != null) { {
if (registeredHandle != null)
{
registeredHandle.Unregister(null); registeredHandle.Unregister(null);
} }
} }
} }
} }
} }
\ No newline at end of file
...@@ -2,39 +2,41 @@ ...@@ -2,39 +2,41 @@
using System.Collections.Generic; using System.Collections.Generic;
using System.Linq; using System.Linq;
using System.Reflection; using System.Reflection;
using System.Text; using DotNetCore.CAP.Abstractions;
using Cap.Consistency.Abstractions; using DotNetCore.CAP.Infrastructure;
using Cap.Consistency.Consumer;
using Cap.Consistency.Infrastructure;
using Microsoft.Extensions.DependencyInjection; using Microsoft.Extensions.DependencyInjection;
namespace Cap.Consistency.Internal namespace DotNetCore.CAP.Internal
{ {
public class ConsumerExcutorSelector : IConsumerExcutorSelector public class ConsumerExcutorSelector : IConsumerExcutorSelector
{ {
private readonly IServiceProvider _serviceProvider; private readonly IServiceProvider _serviceProvider;
public ConsumerExcutorSelector(IServiceProvider serviceProvider) { public ConsumerExcutorSelector(IServiceProvider serviceProvider)
{
_serviceProvider = serviceProvider; _serviceProvider = serviceProvider;
} }
public ConsumerExecutorDescriptor SelectBestCandidate(string key, IReadOnlyList<ConsumerExecutorDescriptor> executeDescriptor) { public ConsumerExecutorDescriptor SelectBestCandidate(string key, IReadOnlyList<ConsumerExecutorDescriptor> executeDescriptor)
{
return executeDescriptor.FirstOrDefault(x => x.Attribute.Name == key); return executeDescriptor.FirstOrDefault(x => x.Attribute.Name == key);
} }
public IReadOnlyList<ConsumerExecutorDescriptor> SelectCandidates(TopicContext context) { public IReadOnlyList<ConsumerExecutorDescriptor> SelectCandidates(TopicContext context)
{
var consumerServices = context.ServiceProvider.GetServices<IConsumerService>(); var consumerServices = context.ServiceProvider.GetServices<IConsumerService>();
var executorDescriptorList = new List<ConsumerExecutorDescriptor>(); var executorDescriptorList = new List<ConsumerExecutorDescriptor>();
foreach (var service in consumerServices) { foreach (var service in consumerServices)
{
var typeInfo = service.GetType().GetTypeInfo(); var typeInfo = service.GetType().GetTypeInfo();
if (!typeof(IConsumerService).GetTypeInfo().IsAssignableFrom(typeInfo)) { if (!typeof(IConsumerService).GetTypeInfo().IsAssignableFrom(typeInfo))
{
continue; continue;
} }
foreach (var method in typeInfo.DeclaredMethods) { foreach (var method in typeInfo.DeclaredMethods)
{
var topicAttr = method.GetCustomAttribute<TopicAttribute>(true); var topicAttr = method.GetCustomAttribute<TopicAttribute>(true);
if (topicAttr == null) continue; if (topicAttr == null) continue;
...@@ -44,16 +46,20 @@ namespace Cap.Consistency.Internal ...@@ -44,16 +46,20 @@ namespace Cap.Consistency.Internal
return executorDescriptorList; return executorDescriptorList;
} }
private ConsumerExecutorDescriptor InitDescriptor(TopicAttribute attr,
MethodInfo methodInfo, TypeInfo implType
) {
var descriptor = new ConsumerExecutorDescriptor();
descriptor.Attribute = attr; private ConsumerExecutorDescriptor InitDescriptor(
descriptor.MethodInfo = methodInfo; TopicAttribute attr,
descriptor.ImplTypeInfo = implType; MethodInfo methodInfo,
TypeInfo implType)
{
var descriptor = new ConsumerExecutorDescriptor()
{
Attribute = attr,
MethodInfo = methodInfo,
ImplTypeInfo = implType
};
return descriptor; return descriptor;
} }
} }
} }
\ No newline at end of file
using System; using System;
using System.Collections.Generic;
using System.Reflection;
using System.Text; using System.Text;
using System.Threading.Tasks; using System.Threading.Tasks;
using Cap.Consistency.Abstractions; using DotNetCore.CAP.Abstractions;
using Cap.Consistency.Abstractions.ModelBinding; using DotNetCore.CAP.Abstractions.ModelBinding;
using Microsoft.Extensions.DependencyInjection; using Microsoft.Extensions.DependencyInjection;
using Microsoft.Extensions.Logging; using Microsoft.Extensions.Logging;
using Newtonsoft.Json;
namespace Cap.Consistency.Internal namespace DotNetCore.CAP.Internal
{ {
public class ConsumerInvoker : IConsumerInvoker public class ConsumerInvoker : IConsumerInvoker
{ {
...@@ -22,8 +19,8 @@ namespace Cap.Consistency.Internal ...@@ -22,8 +19,8 @@ namespace Cap.Consistency.Internal
public ConsumerInvoker(ILogger logger, public ConsumerInvoker(ILogger logger,
IServiceProvider serviceProvider, IServiceProvider serviceProvider,
IModelBinder modelBinder, IModelBinder modelBinder,
ConsumerContext consumerContext) { ConsumerContext consumerContext)
{
_logger = logger ?? throw new ArgumentNullException(nameof(logger)); _logger = logger ?? throw new ArgumentNullException(nameof(logger));
_serviceProvider = serviceProvider; _serviceProvider = serviceProvider;
_modelBinder = modelBinder; _modelBinder = modelBinder;
...@@ -32,43 +29,45 @@ namespace Cap.Consistency.Internal ...@@ -32,43 +29,45 @@ namespace Cap.Consistency.Internal
_consumerContext.ConsumerDescriptor.ImplTypeInfo); _consumerContext.ConsumerDescriptor.ImplTypeInfo);
} }
public Task InvokeAsync()
public Task InvokeAsync() { {
try { try
using (_logger.BeginScope("consumer invoker begin")) { {
using (_logger.BeginScope("consumer invoker begin"))
{
_logger.LogDebug("Executing consumer Topic: {0}", _consumerContext.ConsumerDescriptor.Attribute); _logger.LogDebug("Executing consumer Topic: {0}", _consumerContext.ConsumerDescriptor.Attribute);
try { try
{
var obj = ActivatorUtilities.GetServiceOrCreateInstance(_serviceProvider, _consumerContext.ConsumerDescriptor.ImplTypeInfo.AsType()); var obj = ActivatorUtilities.GetServiceOrCreateInstance(_serviceProvider, _consumerContext.ConsumerDescriptor.ImplTypeInfo.AsType());
var bodyString = Encoding.UTF8.GetString(_consumerContext.DeliverMessage.Body); var bodyString = Encoding.UTF8.GetString(_consumerContext.DeliverMessage.Body);
if (_executor.MethodParameters.Length > 0) { if (_executor.MethodParameters.Length > 0)
{
var firstParameter = _executor.MethodParameters[0]; var firstParameter = _executor.MethodParameters[0];
var bindingContext = ModelBindingContext.CreateBindingContext(bodyString, var bindingContext = ModelBindingContext.CreateBindingContext(bodyString,
firstParameter.Name, firstParameter.ParameterType); firstParameter.Name, firstParameter.ParameterType);
_modelBinder.BindModelAsync(bindingContext); _modelBinder.BindModelAsync(bindingContext);
_executor.Execute(obj, bindingContext.Result); _executor.Execute(obj, bindingContext.Result);
} }
else { else
{
_executor.Execute(obj); _executor.Execute(obj);
} }
return Task.CompletedTask; return Task.CompletedTask;
} }
finally { finally
{
_logger.LogDebug("Executed consumer method ."); _logger.LogDebug("Executed consumer method .");
} }
} }
} }
finally { finally
{
} }
} }
} }
} }
\ No newline at end of file
using System; using System;
using System.Collections.Generic; using DotNetCore.CAP.Abstractions;
using System.Text; using DotNetCore.CAP.Abstractions.ModelBinding;
using Cap.Consistency.Abstractions; using DotNetCore.CAP.Infrastructure;
using Cap.Consistency.Abstractions.ModelBinding;
using Cap.Consistency.Infrastructure;
using Microsoft.Extensions.Logging; using Microsoft.Extensions.Logging;
namespace Cap.Consistency.Internal namespace DotNetCore.CAP.Internal
{ {
public class ConsumerInvokerFactory : IConsumerInvokerFactory public class ConsumerInvokerFactory : IConsumerInvokerFactory
{ {
...@@ -17,15 +15,15 @@ namespace Cap.Consistency.Internal ...@@ -17,15 +15,15 @@ namespace Cap.Consistency.Internal
public ConsumerInvokerFactory( public ConsumerInvokerFactory(
ILoggerFactory loggerFactory, ILoggerFactory loggerFactory,
IModelBinder modelBinder, IModelBinder modelBinder,
IServiceProvider serviceProvider) { IServiceProvider serviceProvider)
{
_logger = loggerFactory.CreateLogger<ConsumerInvokerFactory>(); _logger = loggerFactory.CreateLogger<ConsumerInvokerFactory>();
_modelBinder = modelBinder; _modelBinder = modelBinder;
_serviceProvider = serviceProvider; _serviceProvider = serviceProvider;
} }
public IConsumerInvoker CreateInvoker(ConsumerContext consumerContext) { public IConsumerInvoker CreateInvoker(ConsumerContext consumerContext)
{
var context = new ConsumerInvokerContext(consumerContext); var context = new ConsumerInvokerContext(consumerContext);
context.Result = new ConsumerInvoker(_logger, _serviceProvider, _modelBinder, consumerContext); context.Result = new ConsumerInvoker(_logger, _serviceProvider, _modelBinder, consumerContext);
...@@ -33,4 +31,4 @@ namespace Cap.Consistency.Internal ...@@ -33,4 +31,4 @@ namespace Cap.Consistency.Internal
return context.Result; return context.Result;
} }
} }
} }
\ No newline at end of file
using System; using System.Collections.Generic;
using System.Collections.Generic;
using System.Text;
namespace Cap.Consistency.Internal namespace DotNetCore.CAP.Internal
{ {
public class ConsumerMethodExecutor public class ConsumerMethodExecutor
{ {
public static object[] PrepareArguments( public static object[] PrepareArguments(
IDictionary<string, object> actionParameters, IDictionary<string, object> actionParameters,
ObjectMethodExecutor actionMethodExecutor) { ObjectMethodExecutor actionMethodExecutor)
{
var declaredParameterInfos = actionMethodExecutor.MethodParameters; var declaredParameterInfos = actionMethodExecutor.MethodParameters;
var count = declaredParameterInfos.Length; var count = declaredParameterInfos.Length;
if (count == 0) { if (count == 0)
{
return null; return null;
} }
var arguments = new object[count]; var arguments = new object[count];
for (var index = 0; index < count; index++) { for (var index = 0; index < count; index++)
{
var parameterInfo = declaredParameterInfos[index]; var parameterInfo = declaredParameterInfos[index];
object value; object value;
if (!actionParameters.TryGetValue(parameterInfo.Name, out value)) { if (!actionParameters.TryGetValue(parameterInfo.Name, out value))
{
value = actionMethodExecutor.GetDefaultValueForParameter(index); value = actionMethodExecutor.GetDefaultValueForParameter(index);
} }
...@@ -30,4 +32,4 @@ namespace Cap.Consistency.Internal ...@@ -30,4 +32,4 @@ namespace Cap.Consistency.Internal
return arguments; return arguments;
} }
} }
} }
\ No newline at end of file
using System; using System;
using System.Collections.Generic;
using System.Linq.Expressions; using System.Linq.Expressions;
using System.Reflection; using System.Reflection;
using System.Text;
using System.Threading.Tasks; using System.Threading.Tasks;
using Cap.Consistency.Abstractions.ModelBinding; using DotNetCore.CAP.Abstractions.ModelBinding;
using Newtonsoft.Json; using Newtonsoft.Json;
namespace Cap.Consistency.Internal namespace DotNetCore.CAP.Internal
{ {
public class DefaultModelBinder : IModelBinder public class DefaultModelBinder : IModelBinder
{ {
private Func<object> _modelCreator; private Func<object> _modelCreator;
public Task BindModelAsync(ModelBindingContext bindingContext) { public Task BindModelAsync(ModelBindingContext bindingContext)
{
if (bindingContext.Model == null) { if (bindingContext.Model == null)
{
bindingContext.Model = CreateModel(bindingContext); bindingContext.Model = CreateModel(bindingContext);
} }
bindingContext.Result = JsonConvert.DeserializeObject(bindingContext.Values, bindingContext.ModelType); bindingContext.Result = JsonConvert.DeserializeObject(bindingContext.Values, bindingContext.ModelType);
return Task.CompletedTask; return Task.CompletedTask;
} }
protected virtual object CreateModel(ModelBindingContext bindingContext) { protected virtual object CreateModel(ModelBindingContext bindingContext)
if (bindingContext == null) { {
if (bindingContext == null)
{
throw new ArgumentNullException(nameof(bindingContext)); throw new ArgumentNullException(nameof(bindingContext));
} }
if (_modelCreator == null) { if (_modelCreator == null)
{
var modelTypeInfo = bindingContext.ModelType.GetTypeInfo(); var modelTypeInfo = bindingContext.ModelType.GetTypeInfo();
if (modelTypeInfo.IsAbstract || modelTypeInfo.GetConstructor(Type.EmptyTypes) == null) { if (modelTypeInfo.IsAbstract || modelTypeInfo.GetConstructor(Type.EmptyTypes) == null)
{
throw new InvalidOperationException(); throw new InvalidOperationException();
} }
...@@ -45,4 +46,4 @@ namespace Cap.Consistency.Internal ...@@ -45,4 +46,4 @@ namespace Cap.Consistency.Internal
return _modelCreator(); return _modelCreator();
} }
} }
} }
\ No newline at end of file
using System; using System;
using System.Collections.Concurrent; using System.Collections.Concurrent;
using System.Collections.Generic; using DotNetCore.CAP.Abstractions;
using System.Text; using DotNetCore.CAP.Infrastructure;
using Cap.Consistency.Abstractions;
using Cap.Consistency.Infrastructure;
namespace Cap.Consistency.Internal namespace DotNetCore.CAP.Internal
{ {
public class MethodMatcherCache public class MethodMatcherCache
{ {
private readonly IConsumerExcutorSelector _selector; private readonly IConsumerExcutorSelector _selector;
public MethodMatcherCache(IConsumerExcutorSelector selector) { public MethodMatcherCache(IConsumerExcutorSelector selector)
{
_selector = selector; _selector = selector;
} }
public ConcurrentDictionary<string, ConsumerExecutorDescriptor> GetCandidatesMethods(TopicContext routeContext) { public ConcurrentDictionary<string, ConsumerExecutorDescriptor> GetCandidatesMethods(TopicContext routeContext)
{
if (Entries.Count == 0) { if (Entries.Count == 0)
{
var executorCollection = _selector.SelectCandidates(routeContext); var executorCollection = _selector.SelectCandidates(routeContext);
foreach (var item in executorCollection) { foreach (var item in executorCollection)
{
Entries.GetOrAdd(item.Attribute.Name, item); Entries.GetOrAdd(item.Attribute.Name, item);
} }
} }
return Entries; return Entries;
} }
public ConsumerExecutorDescriptor GetTopicExector(string topicName) { public ConsumerExecutorDescriptor GetTopicExector(string topicName)
{
if (Entries == null) { if (Entries == null)
{
throw new ArgumentNullException(nameof(Entries)); throw new ArgumentNullException(nameof(Entries));
} }
...@@ -41,4 +41,4 @@ namespace Cap.Consistency.Internal ...@@ -41,4 +41,4 @@ namespace Cap.Consistency.Internal
public ConcurrentDictionary<string, ConsumerExecutorDescriptor> Entries { get; } = public ConcurrentDictionary<string, ConsumerExecutorDescriptor> Entries { get; } =
new ConcurrentDictionary<string, ConsumerExecutorDescriptor>(); new ConcurrentDictionary<string, ConsumerExecutorDescriptor>();
} }
} }
\ No newline at end of file
...@@ -2,9 +2,8 @@ ...@@ -2,9 +2,8 @@
using System.Collections.Generic; using System.Collections.Generic;
using System.Linq; using System.Linq;
using System.Reflection; using System.Reflection;
using System.Text;
namespace Cap.Consistency.Internal namespace DotNetCore.CAP.Internal
{ {
/// <summary> /// <summary>
/// Provides access to the combined list of attributes associated a <see cref="Type"/> or property. /// Provides access to the combined list of attributes associated a <see cref="Type"/> or property.
...@@ -15,8 +14,10 @@ namespace Cap.Consistency.Internal ...@@ -15,8 +14,10 @@ namespace Cap.Consistency.Internal
/// Creates a new <see cref="ModelAttributes"/> for a <see cref="Type"/>. /// Creates a new <see cref="ModelAttributes"/> for a <see cref="Type"/>.
/// </summary> /// </summary>
/// <param name="typeAttributes">The set of attributes for the <see cref="Type"/>.</param> /// <param name="typeAttributes">The set of attributes for the <see cref="Type"/>.</param>
public ModelAttributes(IEnumerable<object> typeAttributes) { public ModelAttributes(IEnumerable<object> typeAttributes)
if (typeAttributes == null) { {
if (typeAttributes == null)
{
throw new ArgumentNullException(nameof(typeAttributes)); throw new ArgumentNullException(nameof(typeAttributes));
} }
...@@ -31,12 +32,15 @@ namespace Cap.Consistency.Internal ...@@ -31,12 +32,15 @@ namespace Cap.Consistency.Internal
/// <param name="typeAttributes"> /// <param name="typeAttributes">
/// The set of attributes for the property's <see cref="Type"/>. See <see cref="PropertyInfo.PropertyType"/>. /// The set of attributes for the property's <see cref="Type"/>. See <see cref="PropertyInfo.PropertyType"/>.
/// </param> /// </param>
public ModelAttributes(IEnumerable<object> propertyAttributes, IEnumerable<object> typeAttributes) { public ModelAttributes(IEnumerable<object> propertyAttributes, IEnumerable<object> typeAttributes)
if (propertyAttributes == null) { {
if (propertyAttributes == null)
{
throw new ArgumentNullException(nameof(propertyAttributes)); throw new ArgumentNullException(nameof(propertyAttributes));
} }
if (typeAttributes == null) { if (typeAttributes == null)
{
throw new ArgumentNullException(nameof(typeAttributes)); throw new ArgumentNullException(nameof(typeAttributes));
} }
...@@ -72,12 +76,15 @@ namespace Cap.Consistency.Internal ...@@ -72,12 +76,15 @@ namespace Cap.Consistency.Internal
/// <param name="property">A <see cref="PropertyInfo"/> for which attributes need to be resolved. /// <param name="property">A <see cref="PropertyInfo"/> for which attributes need to be resolved.
/// </param> /// </param>
/// <returns>A <see cref="ModelAttributes"/> instance with the attributes of the property.</returns> /// <returns>A <see cref="ModelAttributes"/> instance with the attributes of the property.</returns>
public static ModelAttributes GetAttributesForProperty(Type type, PropertyInfo property) { public static ModelAttributes GetAttributesForProperty(Type type, PropertyInfo property)
if (type == null) { {
if (type == null)
{
throw new ArgumentNullException(nameof(type)); throw new ArgumentNullException(nameof(type));
} }
if (property == null) { if (property == null)
{
throw new ArgumentNullException(nameof(property)); throw new ArgumentNullException(nameof(property));
} }
...@@ -93,8 +100,10 @@ namespace Cap.Consistency.Internal ...@@ -93,8 +100,10 @@ namespace Cap.Consistency.Internal
/// <param name="type">The <see cref="Type"/> for which attributes need to be resolved. /// <param name="type">The <see cref="Type"/> for which attributes need to be resolved.
/// </param> /// </param>
/// <returns>A <see cref="ModelAttributes"/> instance with the attributes of the <see cref="Type"/>.</returns> /// <returns>A <see cref="ModelAttributes"/> instance with the attributes of the <see cref="Type"/>.</returns>
public static ModelAttributes GetAttributesForType(Type type) { public static ModelAttributes GetAttributesForType(Type type)
if (type == null) { {
if (type == null)
{
throw new ArgumentNullException(nameof(type)); throw new ArgumentNullException(nameof(type));
} }
...@@ -103,4 +112,4 @@ namespace Cap.Consistency.Internal ...@@ -103,4 +112,4 @@ namespace Cap.Consistency.Internal
return new ModelAttributes(attributes); return new ModelAttributes(attributes);
} }
} }
} }
\ No newline at end of file
using System; using System;
using System.Collections.Generic;
using System.Text;
using NCrontab; using NCrontab;
namespace Cap.Consistency.Job namespace DotNetCore.CAP.Job
{ {
public class ComputedCronJob public class ComputedCronJob
{ {
private CronJobRegistry.Entry _entry; private CronJobRegistry.Entry _entry;
public ComputedCronJob() { public ComputedCronJob()
{
} }
public ComputedCronJob(CronJob job) { public ComputedCronJob(CronJob job)
{
Job = job; Job = job;
Schedule = CrontabSchedule.Parse(job.Cron); Schedule = CrontabSchedule.Parse(job.Cron);
if (job.TypeName != null) { if (job.TypeName != null)
{
JobType = Type.GetType(job.TypeName); JobType = Type.GetType(job.TypeName);
} }
} }
public ComputedCronJob(CronJob job, CronJobRegistry.Entry entry) public ComputedCronJob(CronJob job, CronJobRegistry.Entry entry)
: this(job) { : this(job)
{
_entry = entry; _entry = entry;
} }
...@@ -40,14 +42,16 @@ namespace Cap.Consistency.Job ...@@ -40,14 +42,16 @@ namespace Cap.Consistency.Job
public RetryBehavior RetryBehavior => _entry.RetryBehavior; public RetryBehavior RetryBehavior => _entry.RetryBehavior;
public void Update(DateTime baseTime) { public void Update(DateTime baseTime)
{
Job.LastRun = baseTime; Job.LastRun = baseTime;
} }
public void UpdateNext(DateTime now) { public void UpdateNext(DateTime now)
{
var next = Schedule.GetNextOccurrence(now); var next = Schedule.GetNextOccurrence(now);
var previousNext = Schedule.GetNextOccurrence(Job.LastRun); var previousNext = Schedule.GetNextOccurrence(Job.LastRun);
Next = next > previousNext ? now : next; Next = next > previousNext ? now : next;
} }
} }
} }
\ No newline at end of file
using System; using System;
using System.Collections.Generic;
using System.Text;
namespace Cap.Consistency.Job namespace DotNetCore.CAP.Job
{ {
public class Cron public class Cron
{ {
/// <summary> /// <summary>
/// Returns cron expression that fires every minute. /// Returns cron expression that fires every minute.
/// </summary> /// </summary>
public static string Minutely() { public static string Minutely()
{
return "* * * * *"; return "* * * * *";
} }
/// <summary> /// <summary>
/// Returns cron expression that fires every hour at the first minute. /// Returns cron expression that fires every hour at the first minute.
/// </summary> /// </summary>
public static string Hourly() { public static string Hourly()
{
return Hourly(minute: 0); return Hourly(minute: 0);
} }
...@@ -24,14 +24,16 @@ namespace Cap.Consistency.Job ...@@ -24,14 +24,16 @@ namespace Cap.Consistency.Job
/// Returns cron expression that fires every hour at the specified minute. /// Returns cron expression that fires every hour at the specified minute.
/// </summary> /// </summary>
/// <param name="minute">The minute in which the schedule will be activated (0-59).</param> /// <param name="minute">The minute in which the schedule will be activated (0-59).</param>
public static string Hourly(int minute) { public static string Hourly(int minute)
{
return string.Format("{0} * * * *", minute); return string.Format("{0} * * * *", minute);
} }
/// <summary> /// <summary>
/// Returns cron expression that fires every day at 00:00 UTC. /// Returns cron expression that fires every day at 00:00 UTC.
/// </summary> /// </summary>
public static string Daily() { public static string Daily()
{
return Daily(hour: 0); return Daily(hour: 0);
} }
...@@ -40,7 +42,8 @@ namespace Cap.Consistency.Job ...@@ -40,7 +42,8 @@ namespace Cap.Consistency.Job
/// the specified hour in UTC. /// the specified hour in UTC.
/// </summary> /// </summary>
/// <param name="hour">The hour in which the schedule will be activated (0-23).</param> /// <param name="hour">The hour in which the schedule will be activated (0-23).</param>
public static string Daily(int hour) { public static string Daily(int hour)
{
return Daily(hour, minute: 0); return Daily(hour, minute: 0);
} }
...@@ -50,14 +53,16 @@ namespace Cap.Consistency.Job ...@@ -50,14 +53,16 @@ namespace Cap.Consistency.Job
/// </summary> /// </summary>
/// <param name="hour">The hour in which the schedule will be activated (0-23).</param> /// <param name="hour">The hour in which the schedule will be activated (0-23).</param>
/// <param name="minute">The minute in which the schedule will be activated (0-59).</param> /// <param name="minute">The minute in which the schedule will be activated (0-59).</param>
public static string Daily(int hour, int minute) { public static string Daily(int hour, int minute)
{
return string.Format("{0} {1} * * *", minute, hour); return string.Format("{0} {1} * * *", minute, hour);
} }
/// <summary> /// <summary>
/// Returns cron expression that fires every week at Monday, 00:00 UTC. /// Returns cron expression that fires every week at Monday, 00:00 UTC.
/// </summary> /// </summary>
public static string Weekly() { public static string Weekly()
{
return Weekly(DayOfWeek.Monday); return Weekly(DayOfWeek.Monday);
} }
...@@ -66,7 +71,8 @@ namespace Cap.Consistency.Job ...@@ -66,7 +71,8 @@ namespace Cap.Consistency.Job
/// day of the week. /// day of the week.
/// </summary> /// </summary>
/// <param name="dayOfWeek">The day of week in which the schedule will be activated.</param> /// <param name="dayOfWeek">The day of week in which the schedule will be activated.</param>
public static string Weekly(DayOfWeek dayOfWeek) { public static string Weekly(DayOfWeek dayOfWeek)
{
return Weekly(dayOfWeek, hour: 0); return Weekly(dayOfWeek, hour: 0);
} }
...@@ -76,7 +82,8 @@ namespace Cap.Consistency.Job ...@@ -76,7 +82,8 @@ namespace Cap.Consistency.Job
/// </summary> /// </summary>
/// <param name="dayOfWeek">The day of week in which the schedule will be activated.</param> /// <param name="dayOfWeek">The day of week in which the schedule will be activated.</param>
/// <param name="hour">The hour in which the schedule will be activated (0-23).</param> /// <param name="hour">The hour in which the schedule will be activated (0-23).</param>
public static string Weekly(DayOfWeek dayOfWeek, int hour) { public static string Weekly(DayOfWeek dayOfWeek, int hour)
{
return Weekly(dayOfWeek, hour, minute: 0); return Weekly(dayOfWeek, hour, minute: 0);
} }
...@@ -87,7 +94,8 @@ namespace Cap.Consistency.Job ...@@ -87,7 +94,8 @@ namespace Cap.Consistency.Job
/// <param name="dayOfWeek">The day of week in which the schedule will be activated.</param> /// <param name="dayOfWeek">The day of week in which the schedule will be activated.</param>
/// <param name="hour">The hour in which the schedule will be activated (0-23).</param> /// <param name="hour">The hour in which the schedule will be activated (0-23).</param>
/// <param name="minute">The minute in which the schedule will be activated (0-59).</param> /// <param name="minute">The minute in which the schedule will be activated (0-59).</param>
public static string Weekly(DayOfWeek dayOfWeek, int hour, int minute) { public static string Weekly(DayOfWeek dayOfWeek, int hour, int minute)
{
return string.Format("{0} {1} * * {2}", minute, hour, (int)dayOfWeek); return string.Format("{0} {1} * * {2}", minute, hour, (int)dayOfWeek);
} }
...@@ -95,7 +103,8 @@ namespace Cap.Consistency.Job ...@@ -95,7 +103,8 @@ namespace Cap.Consistency.Job
/// Returns cron expression that fires every month at 00:00 UTC of the first /// Returns cron expression that fires every month at 00:00 UTC of the first
/// day of month. /// day of month.
/// </summary> /// </summary>
public static string Monthly() { public static string Monthly()
{
return Monthly(day: 1); return Monthly(day: 1);
} }
...@@ -104,7 +113,8 @@ namespace Cap.Consistency.Job ...@@ -104,7 +113,8 @@ namespace Cap.Consistency.Job
/// day of month. /// day of month.
/// </summary> /// </summary>
/// <param name="day">The day of month in which the schedule will be activated (1-31).</param> /// <param name="day">The day of month in which the schedule will be activated (1-31).</param>
public static string Monthly(int day) { public static string Monthly(int day)
{
return Monthly(day, hour: 0); return Monthly(day, hour: 0);
} }
...@@ -114,7 +124,8 @@ namespace Cap.Consistency.Job ...@@ -114,7 +124,8 @@ namespace Cap.Consistency.Job
/// </summary> /// </summary>
/// <param name="day">The day of month in which the schedule will be activated (1-31).</param> /// <param name="day">The day of month in which the schedule will be activated (1-31).</param>
/// <param name="hour">The hour in which the schedule will be activated (0-23).</param> /// <param name="hour">The hour in which the schedule will be activated (0-23).</param>
public static string Monthly(int day, int hour) { public static string Monthly(int day, int hour)
{
return Monthly(day, hour, minute: 0); return Monthly(day, hour, minute: 0);
} }
...@@ -125,14 +136,16 @@ namespace Cap.Consistency.Job ...@@ -125,14 +136,16 @@ namespace Cap.Consistency.Job
/// <param name="day">The day of month in which the schedule will be activated (1-31).</param> /// <param name="day">The day of month in which the schedule will be activated (1-31).</param>
/// <param name="hour">The hour in which the schedule will be activated (0-23).</param> /// <param name="hour">The hour in which the schedule will be activated (0-23).</param>
/// <param name="minute">The minute in which the schedule will be activated (0-59).</param> /// <param name="minute">The minute in which the schedule will be activated (0-59).</param>
public static string Monthly(int day, int hour, int minute) { public static string Monthly(int day, int hour, int minute)
{
return string.Format("{0} {1} {2} * *", minute, hour, day); return string.Format("{0} {1} {2} * *", minute, hour, day);
} }
/// <summary> /// <summary>
/// Returns cron expression that fires every year on Jan, 1st at 00:00 UTC. /// Returns cron expression that fires every year on Jan, 1st at 00:00 UTC.
/// </summary> /// </summary>
public static string Yearly() { public static string Yearly()
{
return Yearly(month: 1); return Yearly(month: 1);
} }
...@@ -141,7 +154,8 @@ namespace Cap.Consistency.Job ...@@ -141,7 +154,8 @@ namespace Cap.Consistency.Job
/// of the specified month. /// of the specified month.
/// </summary> /// </summary>
/// <param name="month">The month in which the schedule will be activated (1-12).</param> /// <param name="month">The month in which the schedule will be activated (1-12).</param>
public static string Yearly(int month) { public static string Yearly(int month)
{
return Yearly(month, day: 1); return Yearly(month, day: 1);
} }
...@@ -151,7 +165,8 @@ namespace Cap.Consistency.Job ...@@ -151,7 +165,8 @@ namespace Cap.Consistency.Job
/// </summary> /// </summary>
/// <param name="month">The month in which the schedule will be activated (1-12).</param> /// <param name="month">The month in which the schedule will be activated (1-12).</param>
/// <param name="day">The day of month in which the schedule will be activated (1-31).</param> /// <param name="day">The day of month in which the schedule will be activated (1-31).</param>
public static string Yearly(int month, int day) { public static string Yearly(int month, int day)
{
return Yearly(month, day, hour: 0); return Yearly(month, day, hour: 0);
} }
...@@ -162,7 +177,8 @@ namespace Cap.Consistency.Job ...@@ -162,7 +177,8 @@ namespace Cap.Consistency.Job
/// <param name="month">The month in which the schedule will be activated (1-12).</param> /// <param name="month">The month in which the schedule will be activated (1-12).</param>
/// <param name="day">The day of month in which the schedule will be activated (1-31).</param> /// <param name="day">The day of month in which the schedule will be activated (1-31).</param>
/// <param name="hour">The hour in which the schedule will be activated (0-23).</param> /// <param name="hour">The hour in which the schedule will be activated (0-23).</param>
public static string Yearly(int month, int day, int hour) { public static string Yearly(int month, int day, int hour)
{
return Yearly(month, day, hour, minute: 0); return Yearly(month, day, hour, minute: 0);
} }
...@@ -174,8 +190,9 @@ namespace Cap.Consistency.Job ...@@ -174,8 +190,9 @@ namespace Cap.Consistency.Job
/// <param name="day">The day of month in which the schedule will be activated (1-31).</param> /// <param name="day">The day of month in which the schedule will be activated (1-31).</param>
/// <param name="hour">The hour in which the schedule will be activated (0-23).</param> /// <param name="hour">The hour in which the schedule will be activated (0-23).</param>
/// <param name="minute">The minute in which the schedule will be activated (0-59).</param> /// <param name="minute">The minute in which the schedule will be activated (0-59).</param>
public static string Yearly(int month, int day, int hour, int minute) { public static string Yearly(int month, int day, int hour, int minute)
{
return string.Format("{0} {1} {2} {3} *", minute, hour, day, month); return string.Format("{0} {1} {2} {3} *", minute, hour, day, month);
} }
} }
} }
\ No newline at end of file
using System; using System;
using System.Collections.Generic;
using System.Text;
namespace Cap.Consistency.Job namespace DotNetCore.CAP.Job
{ {
/// <summary> /// <summary>
/// Represents a cron job to be executed at specified intervals of time. /// Represents a cron job to be executed at specified intervals of time.
/// </summary> /// </summary>
public class CronJob public class CronJob
{ {
public CronJob() { public CronJob()
{
Id = Guid.NewGuid().ToString(); Id = Guid.NewGuid().ToString();
} }
public CronJob(string cron) public CronJob(string cron)
: this() { : this()
{
Cron = cron; Cron = cron;
} }
public CronJob(string cron, DateTime lastRun) public CronJob(string cron, DateTime lastRun)
: this(cron) { : this(cron)
{
LastRun = lastRun; LastRun = lastRun;
} }
...@@ -33,4 +34,4 @@ namespace Cap.Consistency.Job ...@@ -33,4 +34,4 @@ namespace Cap.Consistency.Job
public DateTime LastRun { get; set; } public DateTime LastRun { get; set; }
} }
} }
\ No newline at end of file
using System; using DotNetCore.CAP.Infrastructure;
using System.Collections.Generic;
using System.Text;
using Cap.Consistency.Infrastructure;
using Microsoft.Extensions.Options; using Microsoft.Extensions.Options;
namespace Cap.Consistency.Job namespace DotNetCore.CAP.Job
{ {
public class DefaultCronJobRegistry : CronJobRegistry public class DefaultCronJobRegistry : CronJobRegistry
{ {
private readonly ConsistencyOptions _options; private readonly ConsistencyOptions _options;
public DefaultCronJobRegistry(IOptions<ConsistencyOptions> options) { public DefaultCronJobRegistry(IOptions<ConsistencyOptions> options)
{
_options = options.Value; _options = options.Value;
RegisterJob<CapJob>(nameof(DefaultCronJobRegistry), _options.CronExp, RetryBehavior.DefaultRetry); RegisterJob<CapJob>(nameof(DefaultCronJobRegistry), _options.CronExp, RetryBehavior.DefaultRetry);
} }
} }
} }
\ No newline at end of file
using System; using System;
using System.Collections.Generic; using System.Collections.Generic;
using System.Reflection; using System.Reflection;
using System.Text;
using NCrontab; using NCrontab;
namespace Cap.Consistency.Job namespace DotNetCore.CAP.Job
{ {
public abstract class CronJobRegistry public abstract class CronJobRegistry
{ {
private List<Entry> _entries; private List<Entry> _entries;
public CronJobRegistry() { public CronJobRegistry()
{
_entries = new List<Entry>(); _entries = new List<Entry>();
} }
protected void RegisterJob<T>(string name, string cron, RetryBehavior retryBehavior = null) protected void RegisterJob<T>(string name, string cron, RetryBehavior retryBehavior = null)
where T : IJob { where T : IJob
{
RegisterJob(name, typeof(T), cron, retryBehavior); RegisterJob(name, typeof(T), cron, retryBehavior);
} }
...@@ -26,7 +27,8 @@ namespace Cap.Consistency.Job ...@@ -26,7 +27,8 @@ namespace Cap.Consistency.Job
/// <param name="jobType">The job's type.</param> /// <param name="jobType">The job's type.</param>
/// <param name="cron">The cron expression to use.</param> /// <param name="cron">The cron expression to use.</param>
/// <param name="retryBehavior">The <see cref="RetryBehavior"/> to use.</param> /// <param name="retryBehavior">The <see cref="RetryBehavior"/> to use.</param>
protected void RegisterJob(string name, Type jobType, string cron, RetryBehavior retryBehavior = null) { protected void RegisterJob(string name, Type jobType, string cron, RetryBehavior retryBehavior = null)
{
if (string.IsNullOrWhiteSpace(name)) throw new ArgumentException(nameof(cron)); if (string.IsNullOrWhiteSpace(name)) throw new ArgumentException(nameof(cron));
if (jobType == null) throw new ArgumentNullException(nameof(jobType)); if (jobType == null) throw new ArgumentNullException(nameof(jobType));
if (cron == null) throw new ArgumentNullException(nameof(cron)); if (cron == null) throw new ArgumentNullException(nameof(cron));
...@@ -34,7 +36,8 @@ namespace Cap.Consistency.Job ...@@ -34,7 +36,8 @@ namespace Cap.Consistency.Job
CrontabSchedule.TryParse(cron); CrontabSchedule.TryParse(cron);
if (!typeof(IJob).GetTypeInfo().IsAssignableFrom(jobType)) { if (!typeof(IJob).GetTypeInfo().IsAssignableFrom(jobType))
{
throw new ArgumentException( throw new ArgumentException(
"Cron jobs should extend IJob.", nameof(jobType)); "Cron jobs should extend IJob.", nameof(jobType));
} }
...@@ -46,7 +49,8 @@ namespace Cap.Consistency.Job ...@@ -46,7 +49,8 @@ namespace Cap.Consistency.Job
public class Entry public class Entry
{ {
public Entry(string name, Type jobType, string cron) { public Entry(string name, Type jobType, string cron)
{
Name = name; Name = name;
JobType = jobType; JobType = jobType;
Cron = cron; Cron = cron;
...@@ -61,4 +65,4 @@ namespace Cap.Consistency.Job ...@@ -61,4 +65,4 @@ namespace Cap.Consistency.Job
public RetryBehavior RetryBehavior { get; set; } public RetryBehavior RetryBehavior { get; set; }
} }
} }
} }
\ No newline at end of file
using System; using System;
using System.Collections.Generic;
using System.Text;
using System.Threading.Tasks; using System.Threading.Tasks;
namespace Cap.Consistency.Job namespace DotNetCore.CAP.Job
{ {
public class CapJob : IJob public class CapJob : IJob
{ {
public Task ExecuteAsync()
public Task ExecuteAsync() { {
Console.WriteLine("当前时间:" + DateTime.Now.ToString()); Console.WriteLine("当前时间:" + DateTime.Now.ToString());
return Task.CompletedTask; return Task.CompletedTask;
} }
} }
} }
\ No newline at end of file
using System; using System.Threading.Tasks;
using System.Collections.Generic;
using System.Text;
using System.Threading.Tasks;
namespace Cap.Consistency.Job namespace DotNetCore.CAP.Job
{ {
public interface IJob public interface IJob
{ {
...@@ -12,4 +9,4 @@ namespace Cap.Consistency.Job ...@@ -12,4 +9,4 @@ namespace Cap.Consistency.Job
/// </summary> /// </summary>
Task ExecuteAsync(); Task ExecuteAsync();
} }
} }
\ No newline at end of file
...@@ -3,13 +3,13 @@ using System.Collections.Generic; ...@@ -3,13 +3,13 @@ using System.Collections.Generic;
using System.Linq; using System.Linq;
using System.Threading; using System.Threading;
using System.Threading.Tasks; using System.Threading.Tasks;
using Cap.Consistency.Infrastructure; using DotNetCore.CAP.Infrastructure;
using Cap.Consistency.Job; using DotNetCore.CAP.Job;
using Microsoft.Extensions.DependencyInjection; using Microsoft.Extensions.DependencyInjection;
using Microsoft.Extensions.Logging; using Microsoft.Extensions.Logging;
using Microsoft.Extensions.Options; using Microsoft.Extensions.Options;
namespace Cap.Consistency namespace DotNetCore.CAP
{ {
public class JobProcessingServer : IProcessingServer, IDisposable public class JobProcessingServer : IProcessingServer, IDisposable
{ {
...@@ -29,8 +29,8 @@ namespace Cap.Consistency ...@@ -29,8 +29,8 @@ namespace Cap.Consistency
ILoggerFactory loggerFactory, ILoggerFactory loggerFactory,
IServiceProvider provider, IServiceProvider provider,
DefaultCronJobRegistry defaultJobRegistry, DefaultCronJobRegistry defaultJobRegistry,
IOptions<ConsistencyOptions> options) { IOptions<ConsistencyOptions> options)
{
_logger = logger; _logger = logger;
_loggerFactory = loggerFactory; _loggerFactory = loggerFactory;
_provider = provider; _provider = provider;
...@@ -39,8 +39,8 @@ namespace Cap.Consistency ...@@ -39,8 +39,8 @@ namespace Cap.Consistency
_cts = new CancellationTokenSource(); _cts = new CancellationTokenSource();
} }
public void Start() { public void Start()
{
var processorCount = Environment.ProcessorCount; var processorCount = Environment.ProcessorCount;
processorCount = 1; processorCount = 1;
_processors = GetProcessors(processorCount); _processors = GetProcessors(processorCount);
...@@ -57,40 +57,50 @@ namespace Cap.Consistency ...@@ -57,40 +57,50 @@ namespace Cap.Consistency
_compositeTask = Task.WhenAll(processorTasks); _compositeTask = Task.WhenAll(processorTasks);
} }
public void Dispose() { public void Dispose()
if (_disposed) { {
if (_disposed)
{
return; return;
} }
_disposed = true; _disposed = true;
_logger.ServerShuttingDown(); _logger.ServerShuttingDown();
_cts.Cancel(); _cts.Cancel();
try { try
{
_compositeTask.Wait((int)TimeSpan.FromSeconds(60).TotalMilliseconds); _compositeTask.Wait((int)TimeSpan.FromSeconds(60).TotalMilliseconds);
} }
catch (AggregateException ex) { catch (AggregateException ex)
{
var innerEx = ex.InnerExceptions[0]; var innerEx = ex.InnerExceptions[0];
if (!(innerEx is OperationCanceledException)) { if (!(innerEx is OperationCanceledException))
{
_logger.ExpectedOperationCanceledException(innerEx); _logger.ExpectedOperationCanceledException(innerEx);
} }
} }
} }
private IJobProcessor InfiniteRetry(IJobProcessor inner) { private IJobProcessor InfiniteRetry(IJobProcessor inner)
{
return new InfiniteRetryProcessor(inner, _loggerFactory); return new InfiniteRetryProcessor(inner, _loggerFactory);
} }
private IJobProcessor[] GetProcessors(int processorCount) { private IJobProcessor[] GetProcessors(int processorCount)
{
var returnedProcessors = new List<IJobProcessor>(); var returnedProcessors = new List<IJobProcessor>();
for (int i = 0; i < processorCount; i++) { for (int i = 0; i < processorCount; i++)
{
var processors = _provider.GetServices<IJobProcessor>(); var processors = _provider.GetServices<IJobProcessor>();
foreach (var processor in processors) { foreach (var processor in processors)
if (processor is CronJobProcessor) { {
if (processor is CronJobProcessor)
{
if (i == 0) // only add first cronJob if (i == 0) // only add first cronJob
returnedProcessors.Add(processor); returnedProcessors.Add(processor);
} }
else { else
{
returnedProcessors.Add(processor); returnedProcessors.Add(processor);
} }
} }
...@@ -99,4 +109,4 @@ namespace Cap.Consistency ...@@ -99,4 +109,4 @@ namespace Cap.Consistency
return returnedProcessors.ToArray(); return returnedProcessors.ToArray();
} }
} }
} }
\ No newline at end of file
...@@ -2,12 +2,11 @@ ...@@ -2,12 +2,11 @@
using System.Collections.Generic; using System.Collections.Generic;
using System.Diagnostics; using System.Diagnostics;
using System.Linq; using System.Linq;
using System.Text;
using System.Threading.Tasks; using System.Threading.Tasks;
using Microsoft.Extensions.DependencyInjection; using Microsoft.Extensions.DependencyInjection;
using Microsoft.Extensions.Logging; using Microsoft.Extensions.Logging;
namespace Cap.Consistency.Job namespace DotNetCore.CAP.Job
{ {
public class CronJobProcessor : IJobProcessor public class CronJobProcessor : IJobProcessor
{ {
...@@ -18,8 +17,8 @@ namespace Cap.Consistency.Job ...@@ -18,8 +17,8 @@ namespace Cap.Consistency.Job
public CronJobProcessor( public CronJobProcessor(
DefaultCronJobRegistry jobRegistry, DefaultCronJobRegistry jobRegistry,
ILogger<CronJobProcessor> logger, ILogger<CronJobProcessor> logger,
IServiceProvider provider) { IServiceProvider provider)
{
_jobRegistry = jobRegistry; _jobRegistry = jobRegistry;
_logger = logger; _logger = logger;
_provider = provider; _provider = provider;
...@@ -27,17 +26,20 @@ namespace Cap.Consistency.Job ...@@ -27,17 +26,20 @@ namespace Cap.Consistency.Job
public override string ToString() => nameof(CronJobProcessor); public override string ToString() => nameof(CronJobProcessor);
public Task ProcessAsync(ProcessingContext context) { public Task ProcessAsync(ProcessingContext context)
{
if (context == null) throw new ArgumentNullException(nameof(context)); if (context == null) throw new ArgumentNullException(nameof(context));
return ProcessCoreAsync(context); return ProcessCoreAsync(context);
} }
private async Task ProcessCoreAsync(ProcessingContext context) { private async Task ProcessCoreAsync(ProcessingContext context)
{
//var storage = context.Storage; //var storage = context.Storage;
//var jobs = await GetJobsAsync(storage); //var jobs = await GetJobsAsync(storage);
var jobs = GetJobs(); var jobs = GetJobs();
if (!jobs.Any()) { if (!jobs.Any())
{
_logger.CronJobsNotFound(); _logger.CronJobsNotFound();
// This will cancel this processor. // This will cancel this processor.
...@@ -48,52 +50,61 @@ namespace Cap.Consistency.Job ...@@ -48,52 +50,61 @@ namespace Cap.Consistency.Job
context.ThrowIfStopping(); context.ThrowIfStopping();
var computedJobs = Compute(jobs, context.CronJobRegistry.Build()); var computedJobs = Compute(jobs, context.CronJobRegistry.Build());
if (context.IsStopping) { if (context.IsStopping)
{
return; return;
} }
await Task.WhenAll(computedJobs.Select(j => RunAsync(j, context))); await Task.WhenAll(computedJobs.Select(j => RunAsync(j, context)));
} }
private async Task RunAsync(ComputedCronJob computedJob, ProcessingContext context) { private async Task RunAsync(ComputedCronJob computedJob, ProcessingContext context)
{
//var storage = context.Storage; //var storage = context.Storage;
var retryBehavior = computedJob.RetryBehavior; var retryBehavior = computedJob.RetryBehavior;
while (!context.IsStopping) { while (!context.IsStopping)
{
var now = DateTime.UtcNow; var now = DateTime.UtcNow;
var due = ComputeDue(computedJob, now); var due = ComputeDue(computedJob, now);
var timeSpan = due - now; var timeSpan = due - now;
if (timeSpan.TotalSeconds > 0) { if (timeSpan.TotalSeconds > 0)
{
await context.WaitAsync(timeSpan); await context.WaitAsync(timeSpan);
} }
context.ThrowIfStopping(); context.ThrowIfStopping();
using (var scopedContext = context.CreateScope()) { using (var scopedContext = context.CreateScope())
{
var provider = scopedContext.Provider; var provider = scopedContext.Provider;
var job = provider.GetService<IJob>(); var job = provider.GetService<IJob>();
var success = true; var success = true;
try { try
{
var sw = Stopwatch.StartNew(); var sw = Stopwatch.StartNew();
await job.ExecuteAsync(); await job.ExecuteAsync();
sw.Stop(); sw.Stop();
computedJob.Retries = 0; computedJob.Retries = 0;
_logger.CronJobExecuted(computedJob.Job.Name, sw.Elapsed.TotalSeconds); _logger.CronJobExecuted(computedJob.Job.Name, sw.Elapsed.TotalSeconds);
} }
catch (Exception ex) { catch (Exception ex)
{
success = false; success = false;
if (computedJob.Retries == 0) { if (computedJob.Retries == 0)
{
computedJob.FirstTry = DateTime.UtcNow; computedJob.FirstTry = DateTime.UtcNow;
} }
computedJob.Retries++; computedJob.Retries++;
_logger.CronJobFailed(computedJob.Job.Name, ex); _logger.CronJobFailed(computedJob.Job.Name, ex);
} }
if (success) { if (success)
{
//var connection = provider.GetRequiredService<IStorageConnection>(); //var connection = provider.GetRequiredService<IStorageConnection>();
//await connection.AttachCronJobAsync(computedJob.Job); //await connection.AttachCronJobAsync(computedJob.Job);
...@@ -105,24 +116,28 @@ namespace Cap.Consistency.Job ...@@ -105,24 +116,28 @@ namespace Cap.Consistency.Job
} }
} }
private DateTime ComputeDue(ComputedCronJob computedJob, DateTime now) { private DateTime ComputeDue(ComputedCronJob computedJob, DateTime now)
{
computedJob.UpdateNext(now); computedJob.UpdateNext(now);
var retryBehavior = computedJob.RetryBehavior ?? RetryBehavior.DefaultRetry; var retryBehavior = computedJob.RetryBehavior ?? RetryBehavior.DefaultRetry;
var retries = computedJob.Retries; var retries = computedJob.Retries;
if (retries == 0) { if (retries == 0)
{
return computedJob.Next; return computedJob.Next;
} }
var realNext = computedJob.Schedule.GetNextOccurrence(now); var realNext = computedJob.Schedule.GetNextOccurrence(now);
if (!retryBehavior.Retry) { if (!retryBehavior.Retry)
{
// No retry. If job failed before, we don't care, just schedule it next as usual. // No retry. If job failed before, we don't care, just schedule it next as usual.
return realNext; return realNext;
} }
if (retries >= retryBehavior.RetryCount) { if (retries >= retryBehavior.RetryCount)
{
// Max retries. Just schedule it for the next occurance. // Max retries. Just schedule it for the next occurance.
return realNext; return realNext;
} }
...@@ -131,11 +146,14 @@ namespace Cap.Consistency.Job ...@@ -131,11 +146,14 @@ namespace Cap.Consistency.Job
return computedJob.FirstTry.AddSeconds(retryBehavior.RetryIn(retries)); return computedJob.FirstTry.AddSeconds(retryBehavior.RetryIn(retries));
} }
private CronJob[] GetJobs() { private CronJob[] GetJobs()
{
var cronJobs = new List<CronJob>(); var cronJobs = new List<CronJob>();
var entries = _jobRegistry.Build() ?? new CronJobRegistry.Entry[0]; var entries = _jobRegistry.Build() ?? new CronJobRegistry.Entry[0];
foreach (var entry in entries) { foreach (var entry in entries)
cronJobs.Add(new CronJob { {
cronJobs.Add(new CronJob
{
Name = entry.Name, Name = entry.Name,
TypeName = entry.JobType.AssemblyQualifiedName, TypeName = entry.JobType.AssemblyQualifiedName,
Cron = entry.Cron, Cron = entry.Cron,
...@@ -148,9 +166,10 @@ namespace Cap.Consistency.Job ...@@ -148,9 +166,10 @@ namespace Cap.Consistency.Job
private ComputedCronJob[] Compute(IEnumerable<CronJob> jobs, CronJobRegistry.Entry[] entries) private ComputedCronJob[] Compute(IEnumerable<CronJob> jobs, CronJobRegistry.Entry[] entries)
=> jobs.Select(j => CreateComputedCronJob(j, entries)).ToArray(); => jobs.Select(j => CreateComputedCronJob(j, entries)).ToArray();
private ComputedCronJob CreateComputedCronJob(CronJob job, CronJobRegistry.Entry[] entries) { private ComputedCronJob CreateComputedCronJob(CronJob job, CronJobRegistry.Entry[] entries)
{
var entry = entries.First(e => e.Name == job.Name); var entry = entries.First(e => e.Name == job.Name);
return new ComputedCronJob(job, entry); return new ComputedCronJob(job, entry);
} }
} }
} }
\ No newline at end of file
using System; using System;
using System.Collections.Generic;
using System.Text;
using System.Threading.Tasks; using System.Threading.Tasks;
using Microsoft.Extensions.Logging; using Microsoft.Extensions.Logging;
namespace Cap.Consistency.Job namespace DotNetCore.CAP.Job
{ {
public class InfiniteRetryProcessor : IJobProcessor public class InfiniteRetryProcessor : IJobProcessor
{ {
...@@ -13,22 +11,28 @@ namespace Cap.Consistency.Job ...@@ -13,22 +11,28 @@ namespace Cap.Consistency.Job
public InfiniteRetryProcessor( public InfiniteRetryProcessor(
IJobProcessor inner, IJobProcessor inner,
ILoggerFactory loggerFactory) { ILoggerFactory loggerFactory)
{
_inner = inner; _inner = inner;
_logger = loggerFactory.CreateLogger<InfiniteRetryProcessor>(); _logger = loggerFactory.CreateLogger<InfiniteRetryProcessor>();
} }
public override string ToString() => _inner.ToString(); public override string ToString() => _inner.ToString();
public async Task ProcessAsync(ProcessingContext context) { public async Task ProcessAsync(ProcessingContext context)
while (!context.IsStopping) { {
try { while (!context.IsStopping)
{
try
{
await _inner.ProcessAsync(context); await _inner.ProcessAsync(context);
} }
catch (OperationCanceledException) { catch (OperationCanceledException)
{
return; return;
} }
catch (Exception ex) { catch (Exception ex)
{
_logger.LogWarning( _logger.LogWarning(
1, 1,
ex, ex,
...@@ -37,4 +41,4 @@ namespace Cap.Consistency.Job ...@@ -37,4 +41,4 @@ namespace Cap.Consistency.Job
} }
} }
} }
} }
\ No newline at end of file
using System; using System.Threading.Tasks;
using System.Collections.Generic;
using System.Text;
using System.Threading.Tasks;
namespace Cap.Consistency.Job namespace DotNetCore.CAP.Job
{ {
public interface IJobProcessor public interface IJobProcessor
{ {
Task ProcessAsync(ProcessingContext context); Task ProcessAsync(ProcessingContext context);
} }
} }
\ No newline at end of file
using System; using System;
using System.Collections.Generic;
using System.Text;
using System.Threading; using System.Threading;
using System.Threading.Tasks; using System.Threading.Tasks;
using Microsoft.Extensions.DependencyInjection; using Microsoft.Extensions.DependencyInjection;
namespace Cap.Consistency.Job namespace DotNetCore.CAP.Job
{ {
public class ProcessingContext : IDisposable public class ProcessingContext : IDisposable
{ {
private IServiceScope _scope; private IServiceScope _scope;
private ProcessingContext(ProcessingContext other) { private ProcessingContext(ProcessingContext other)
{
Provider = other.Provider; Provider = other.Provider;
//Storage = other.Storage; //Storage = other.Storage;
CronJobRegistry = other.CronJobRegistry; CronJobRegistry = other.CronJobRegistry;
CancellationToken = other.CancellationToken; CancellationToken = other.CancellationToken;
} }
public ProcessingContext() { public ProcessingContext()
{
} }
public ProcessingContext( public ProcessingContext(
IServiceProvider provider, IServiceProvider provider,
//IStorage storage, //IStorage storage,
CronJobRegistry cronJobRegistry, CronJobRegistry cronJobRegistry,
CancellationToken cancellationToken) { CancellationToken cancellationToken)
{
Provider = provider; Provider = provider;
//Storage = storage; //Storage = storage;
CronJobRegistry = cronJobRegistry; CronJobRegistry = cronJobRegistry;
...@@ -44,23 +45,28 @@ namespace Cap.Consistency.Job ...@@ -44,23 +45,28 @@ namespace Cap.Consistency.Job
public void ThrowIfStopping() => CancellationToken.ThrowIfCancellationRequested(); public void ThrowIfStopping() => CancellationToken.ThrowIfCancellationRequested();
public ProcessingContext CreateScope() { public ProcessingContext CreateScope()
{
var serviceScope = Provider.CreateScope(); var serviceScope = Provider.CreateScope();
return new ProcessingContext(this) { return new ProcessingContext(this)
{
_scope = serviceScope, _scope = serviceScope,
Provider = serviceScope.ServiceProvider Provider = serviceScope.ServiceProvider
}; };
} }
public Task WaitAsync(TimeSpan timeout) { public Task WaitAsync(TimeSpan timeout)
{
return Task.Delay(timeout, CancellationToken); return Task.Delay(timeout, CancellationToken);
} }
public void Dispose() { public void Dispose()
if (_scope != null) { {
if (_scope != null)
{
_scope.Dispose(); _scope.Dispose();
} }
} }
} }
} }
\ No newline at end of file
using System; using System;
using System.Collections.Generic;
using System.Text;
namespace Cap.Consistency.Job namespace DotNetCore.CAP.Job
{ {
public class RetryBehavior public class RetryBehavior
{ {
...@@ -16,7 +14,8 @@ namespace Cap.Consistency.Job ...@@ -16,7 +14,8 @@ namespace Cap.Consistency.Job
private Func<int, int> _retryInThunk; private Func<int, int> _retryInThunk;
static RetryBehavior() { static RetryBehavior()
{
DefaultRetryCount = 25; DefaultRetryCount = 25;
DefaultRetryInThunk = retries => 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)));
...@@ -26,7 +25,8 @@ namespace Cap.Consistency.Job ...@@ -26,7 +25,8 @@ namespace Cap.Consistency.Job
} }
public RetryBehavior(bool retry) public RetryBehavior(bool retry)
: this(retry, DefaultRetryCount, DefaultRetryInThunk) { : this(retry, DefaultRetryCount, DefaultRetryInThunk)
{
} }
/// <summary> /// <summary>
...@@ -35,8 +35,10 @@ namespace Cap.Consistency.Job ...@@ -35,8 +35,10 @@ namespace Cap.Consistency.Job
/// <param name="retry">Whether to retry.</param> /// <param name="retry">Whether to retry.</param>
/// <param name="retryCount">The maximum retry count.</param> /// <param name="retryCount">The maximum retry count.</param>
/// <param name="retryInThunk">The retry in function to use.</param> /// <param name="retryInThunk">The retry in function to use.</param>
public RetryBehavior(bool retry, int retryCount, Func<int, int> retryInThunk) { public RetryBehavior(bool retry, int retryCount, Func<int, int> retryInThunk)
if (retry) { {
if (retry)
{
if (retryCount < 0) throw new ArgumentOutOfRangeException(nameof(retryCount), "Can't be negative."); if (retryCount < 0) throw new ArgumentOutOfRangeException(nameof(retryCount), "Can't be negative.");
} }
...@@ -62,8 +64,9 @@ namespace Cap.Consistency.Job ...@@ -62,8 +64,9 @@ namespace Cap.Consistency.Job
/// </summary> /// </summary>
/// <param name="retries">The current retry count.</param> /// <param name="retries">The current retry count.</param>
/// <returns>The seconds to delay.</returns> /// <returns>The seconds to delay.</returns>
public int RetryIn(int retries) { public int RetryIn(int retries)
{
return _retryInThunk(retries); return _retryInThunk(retries);
} }
} }
} }
\ No newline at end of file
using System; using System;
using System.Collections.Generic; using System.Collections.Generic;
using System.Linq; using System.Linq;
using Cap.Consistency.Job; using DotNetCore.CAP.Job;
using Microsoft.Extensions.Logging; using Microsoft.Extensions.Logging;
namespace Cap.Consistency namespace DotNetCore.CAP
{ {
internal static class LoggerExtensions internal static class LoggerExtensions
{ {
...@@ -17,7 +17,8 @@ namespace Cap.Consistency ...@@ -17,7 +17,8 @@ namespace Cap.Consistency
private static Action<ILogger, string, double, Exception> _cronJobExecuted; private static Action<ILogger, string, double, Exception> _cronJobExecuted;
private static Action<ILogger, string, Exception> _cronJobFailed; private static Action<ILogger, string, Exception> _cronJobFailed;
static LoggerExtensions() { static LoggerExtensions()
{
_serverStarting = LoggerMessage.Define<int, int>( _serverStarting = LoggerMessage.Define<int, int>(
LogLevel.Debug, LogLevel.Debug,
1, 1,
...@@ -52,37 +53,41 @@ namespace Cap.Consistency ...@@ -52,37 +53,41 @@ namespace Cap.Consistency
LogLevel.Warning, LogLevel.Warning,
4, 4,
"Cron job '{jobName}' failed to execute."); "Cron job '{jobName}' failed to execute.");
} }
public static void ServerStarting(this ILogger logger, int machineProcessorCount, int processorCount) { public static void ServerStarting(this ILogger logger, int machineProcessorCount, int processorCount)
{
_serverStarting(logger, machineProcessorCount, processorCount, null); _serverStarting(logger, machineProcessorCount, processorCount, null);
} }
public static void ServerShuttingDown(this ILogger logger) { public static void ServerShuttingDown(this ILogger logger)
{
_serverShuttingDown(logger, null); _serverShuttingDown(logger, null);
} }
public static void ExpectedOperationCanceledException(this ILogger logger, Exception ex) { public static void ExpectedOperationCanceledException(this ILogger logger, Exception ex)
{
_expectedOperationCanceledException(logger, ex.Message, ex); _expectedOperationCanceledException(logger, ex.Message, ex);
} }
public static void CronJobsNotFound(this ILogger logger) { public static void CronJobsNotFound(this ILogger logger)
{
_cronJobsNotFound(logger, null); _cronJobsNotFound(logger, null);
} }
public static void CronJobsScheduling(this ILogger logger, IEnumerable<CronJob> jobs) { public static void CronJobsScheduling(this ILogger logger, IEnumerable<CronJob> jobs)
{
_cronJobsScheduling(logger, jobs.Count(), null); _cronJobsScheduling(logger, jobs.Count(), null);
} }
public static void CronJobExecuted(this ILogger logger, string name, double seconds) { public static void CronJobExecuted(this ILogger logger, string name, double seconds)
{
_cronJobExecuted(logger, name, seconds, null); _cronJobExecuted(logger, name, seconds, null);
} }
public static void CronJobFailed(this ILogger logger, string name, Exception ex) { public static void CronJobFailed(this ILogger logger, string name, Exception ex)
{
_cronJobFailed(logger, name, ex); _cronJobFailed(logger, name, ex);
} }
} }
} }
\ No newline at end of file
using System.Collections.Generic; using System.Collections.Generic;
using System.Linq; using System.Linq;
namespace Cap.Consistency namespace DotNetCore.CAP
{ {
/// <summary> /// <summary>
/// Represents the result of an consistent message operation. /// Represents the result of an consistent message operation.
...@@ -37,9 +37,11 @@ namespace Cap.Consistency ...@@ -37,9 +37,11 @@ namespace Cap.Consistency
/// </summary> /// </summary>
/// <param name="errors">An optional array of <see cref="OperateError"/>s which caused the operation to fail.</param> /// <param name="errors">An optional array of <see cref="OperateError"/>s which caused the operation to fail.</param>
/// <returns>An <see cref="OperateResult"/> indicating a failed operation, with a list of <paramref name="errors"/> if applicable.</returns> /// <returns>An <see cref="OperateResult"/> indicating a failed operation, with a list of <paramref name="errors"/> if applicable.</returns>
public static OperateResult Failed(params OperateError[] errors) { public static OperateResult Failed(params OperateError[] errors)
{
var result = new OperateResult { Succeeded = false }; var result = new OperateResult { Succeeded = false };
if (errors != null) { if (errors != null)
{
result._errors.AddRange(errors); result._errors.AddRange(errors);
} }
return result; return result;
...@@ -53,7 +55,8 @@ namespace Cap.Consistency ...@@ -53,7 +55,8 @@ namespace Cap.Consistency
/// If the operation was successful the ToString() will return "Succeeded" otherwise it returned /// If the operation was successful the ToString() will return "Succeeded" otherwise it returned
/// "Failed : " followed by a comma delimited list of error codes from its <see cref="Errors"/> collection, if any. /// "Failed : " followed by a comma delimited list of error codes from its <see cref="Errors"/> collection, if any.
/// </remarks> /// </remarks>
public override string ToString() { public override string ToString()
{
return Succeeded ? return Succeeded ?
"Succeeded" : "Succeeded" :
string.Format("{0} : {1}", "Failed", string.Join(",", Errors.Select(x => x.Code).ToList())); string.Format("{0} : {1}", "Failed", string.Join(",", Errors.Select(x => x.Code).ToList()));
......
using System; using System;
using System.Threading; using System.Threading;
namespace Cap.Consistency namespace DotNetCore.CAP
{ {
public class TopicContext public class TopicContext
{ {
public TopicContext() { public TopicContext()
{
} }
public TopicContext(IServiceProvider provider, CancellationToken cancellationToken) { public TopicContext(IServiceProvider provider, CancellationToken cancellationToken)
{
ServiceProvider = provider; ServiceProvider = provider;
CancellationToken = cancellationToken; CancellationToken = cancellationToken;
} }
public IServiceProvider ServiceProvider { get; set; } public IServiceProvider ServiceProvider { get; set; }
public CancellationToken CancellationToken { get; } public CancellationToken CancellationToken { get; }
} }
} }
\ No newline at end of file
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("Cap.Consistency.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
...@@ -2,7 +2,7 @@ ...@@ -2,7 +2,7 @@
using Microsoft.EntityFrameworkCore; using Microsoft.EntityFrameworkCore;
using Microsoft.Extensions.DependencyInjection; using Microsoft.Extensions.DependencyInjection;
namespace Cap.Consistency.EntityFrameworkCore.Test namespace DotNetCore.CAP.EntityFrameworkCore.Test
{ {
public static class DbUtil public static class DbUtil
{ {
......
//using System.Threading.Tasks; //using System.Threading.Tasks;
//using Cap.Consistency.Infrastructure; //using DotNetCore.CAP.Infrastructure;
//using Cap.Consistency.Store; //using DotNetCore.CAP.Store;
//using Microsoft.AspNetCore.Builder.Internal; //using Microsoft.AspNetCore.Builder.Internal;
//using Microsoft.AspNetCore.Testing.xunit; //using Microsoft.AspNetCore.Testing.xunit;
//using Microsoft.EntityFrameworkCore; //using Microsoft.EntityFrameworkCore;
//using Microsoft.Extensions.DependencyInjection; //using Microsoft.Extensions.DependencyInjection;
//using Xunit; //using Xunit;
//namespace Cap.Consistency.EntityFrameworkCore.Test //namespace DotNetCore.CAP.EntityFrameworkCore.Test
//{ //{
// public class DefaultPocoTest : IClassFixture<ScratchDatabaseFixture> // public class DefaultPocoTest : IClassFixture<ScratchDatabaseFixture>
// { // {
......
...@@ -3,8 +3,8 @@ ...@@ -3,8 +3,8 @@
<PropertyGroup> <PropertyGroup>
<TargetFramework>netcoreapp1.1</TargetFramework> <TargetFramework>netcoreapp1.1</TargetFramework>
<TreatWarningsAsErrors>true</TreatWarningsAsErrors> <TreatWarningsAsErrors>true</TreatWarningsAsErrors>
<AssemblyName>Cap.Consistency.EntityFrameworkCore.Test</AssemblyName> <AssemblyName>DotNetCore.CAP.EntityFrameworkCore.Test</AssemblyName>
<PackageId>Cap.Consistency.EntityFrameworkCore.Test</PackageId> <PackageId>DotNetCore.CAP.EntityFrameworkCore.Test</PackageId>
<GenerateRuntimeConfigurationFiles>true</GenerateRuntimeConfigurationFiles> <GenerateRuntimeConfigurationFiles>true</GenerateRuntimeConfigurationFiles>
<PackageTargetFallback>$(PackageTargetFallback);dnxcore50;portable-net451+win8</PackageTargetFallback> <PackageTargetFallback>$(PackageTargetFallback);dnxcore50;portable-net451+win8</PackageTargetFallback>
<RuntimeFrameworkVersion>1.1.1</RuntimeFrameworkVersion> <RuntimeFrameworkVersion>1.1.1</RuntimeFrameworkVersion>
...@@ -18,8 +18,8 @@ ...@@ -18,8 +18,8 @@
</ItemGroup> </ItemGroup>
<ItemGroup> <ItemGroup>
<ProjectReference Include="..\..\src\Cap.Consistency\Cap.Consistency.csproj" /> <ProjectReference Include="..\..\src\DotNetCore.CAP\DotNetCore.CAP.csproj" />
<ProjectReference Include="..\..\src\Cap.Consistency.EntityFrameworkCore\Cap.Consistency.EntityFrameworkCore.csproj" /> <ProjectReference Include="..\..\src\DotNetCore.CAP.EntityFrameworkCore\DotNetCore.CAP.EntityFrameworkCore.csproj" />
</ItemGroup> </ItemGroup>
<ItemGroup> <ItemGroup>
......
//using System; //using System;
//using System.Linq; //using System.Linq;
//using System.Threading.Tasks; //using System.Threading.Tasks;
//using Cap.Consistency.Infrastructure; //using DotNetCore.CAP.Infrastructure;
//using Cap.Consistency.Store; //using DotNetCore.CAP.Store;
//using Cap.Consistency.Test; //using DotNetCore.CAP.Test;
//using Microsoft.AspNetCore.Testing; //using Microsoft.AspNetCore.Testing;
//using Microsoft.AspNetCore.Testing.xunit; //using Microsoft.AspNetCore.Testing.xunit;
//using Microsoft.EntityFrameworkCore; //using Microsoft.EntityFrameworkCore;
//using Microsoft.Extensions.DependencyInjection; //using Microsoft.Extensions.DependencyInjection;
//using Xunit; //using Xunit;
//namespace Cap.Consistency.EntityFrameworkCore.Test //namespace DotNetCore.CAP.EntityFrameworkCore.Test
//{ //{
// public class MessageStoreTest : MessageManagerTestBase<ConsistencyMessage>, IClassFixture<ScratchDatabaseFixture> // public class MessageStoreTest : MessageManagerTestBase<ConsistencyMessage>, IClassFixture<ScratchDatabaseFixture>
// { // {
......
//using System; //using System;
//using Cap.Consistency.Infrastructure; //using DotNetCore.CAP.Infrastructure;
//using Cap.Consistency.Store; //using DotNetCore.CAP.Store;
//using Cap.Consistency.Test; //using DotNetCore.CAP.Test;
//using Microsoft.AspNetCore.Testing; //using Microsoft.AspNetCore.Testing;
//using Microsoft.Extensions.DependencyInjection; //using Microsoft.Extensions.DependencyInjection;
//using Xunit; //using Xunit;
//namespace Cap.Consistency.EntityFrameworkCore.Test //namespace DotNetCore.CAP.EntityFrameworkCore.Test
//{ //{
// public class MessageStoreWithGenericsTest : MessageManagerTestBase<MessageWithGenerics, string>, IClassFixture<ScratchDatabaseFixture> // public class MessageStoreWithGenericsTest : MessageManagerTestBase<MessageWithGenerics, string>, IClassFixture<ScratchDatabaseFixture>
// { // {
......
...@@ -6,7 +6,7 @@ using System.Runtime.InteropServices; ...@@ -6,7 +6,7 @@ using System.Runtime.InteropServices;
// associated with an assembly. // associated with an assembly.
[assembly: AssemblyConfiguration("")] [assembly: AssemblyConfiguration("")]
[assembly: AssemblyCompany("")] [assembly: AssemblyCompany("")]
[assembly: AssemblyProduct("Cap.Consistency.EntityFrameworkCore")] [assembly: AssemblyProduct("DotNetCore.CAP.EntityFrameworkCore.Test")]
[assembly: AssemblyTrademark("")] [assembly: AssemblyTrademark("")]
// Setting ComVisible to false makes the types in this assembly not visible // Setting ComVisible to false makes the types in this assembly not visible
...@@ -15,4 +15,4 @@ using System.Runtime.InteropServices; ...@@ -15,4 +15,4 @@ using System.Runtime.InteropServices;
[assembly: ComVisible(false)] [assembly: ComVisible(false)]
// The following GUID is for the ID of the typelib if this project is exposed to COM // The following GUID is for the ID of the typelib if this project is exposed to COM
[assembly: Guid("96111249-c4c3-4dc9-a887-32d583723ab1")] [assembly: Guid("7442c942-1ddc-40e4-8f1b-654e721eaa45")]
\ No newline at end of file \ No newline at end of file
using System; using System;
using Microsoft.EntityFrameworkCore.Internal; using Microsoft.EntityFrameworkCore.Internal;
namespace Cap.Consistency.EntityFrameworkCore.Test namespace DotNetCore.CAP.EntityFrameworkCore.Test
{ {
public class ScratchDatabaseFixture : IDisposable public class ScratchDatabaseFixture : IDisposable
{ {
......
...@@ -4,7 +4,7 @@ using System.Data.SqlClient; ...@@ -4,7 +4,7 @@ using System.Data.SqlClient;
using System.IO; using System.IO;
using System.Threading; using System.Threading;
namespace Cap.Consistency.EntityFrameworkCore.Test namespace DotNetCore.CAP.EntityFrameworkCore.Test
{ {
public class SqlServerTestStore : IDisposable public class SqlServerTestStore : IDisposable
{ {
......
using System.IO; using System.IO;
using Microsoft.Extensions.Configuration; using Microsoft.Extensions.Configuration;
namespace Cap.Consistency.EntityFrameworkCore.Test namespace DotNetCore.CAP.EntityFrameworkCore.Test
{ {
public class TestEnvironment public class TestEnvironment
{ {
......
//using System; //using System;
//using System.Threading; //using System.Threading;
//using System.Threading.Tasks; //using System.Threading.Tasks;
//using Cap.Consistency.Infrastructure; //using DotNetCore.CAP.Infrastructure;
//using Cap.Consistency.Store; //using DotNetCore.CAP.Store;
//using Microsoft.Extensions.DependencyInjection; //using Microsoft.Extensions.DependencyInjection;
//using Xunit; //using Xunit;
//namespace Cap.Consistency.Test //namespace DotNetCore.CAP.Test
//{ //{
// public class ConsistencyBuilderTest // public class ConsistencyBuilderTest
// { // {
......
//using System; //using System;
//using System.Threading; //using System.Threading;
//using System.Threading.Tasks; //using System.Threading.Tasks;
//using Cap.Consistency.Infrastructure; //using DotNetCore.CAP.Infrastructure;
//using Cap.Consistency.Store; //using DotNetCore.CAP.Store;
//using Microsoft.AspNetCore.Http; //using Microsoft.AspNetCore.Http;
//using Microsoft.Extensions.DependencyInjection; //using Microsoft.Extensions.DependencyInjection;
//using Microsoft.Extensions.Logging; //using Microsoft.Extensions.Logging;
//using Moq; //using Moq;
//using Xunit; //using Xunit;
//namespace Cap.Consistency.Test //namespace DotNetCore.CAP.Test
//{ //{
// public class ConsistencyMessageManagerTest // public class ConsistencyMessageManagerTest
// { // {
......
namespace Cap.Consistency.Test namespace CDotNetCore.CAPTest
{ {
public class ConsistencyOptionsTest public class ConsistencyOptionsTest
{ {
......
...@@ -3,8 +3,8 @@ ...@@ -3,8 +3,8 @@
<PropertyGroup> <PropertyGroup>
<TargetFramework>netcoreapp1.1</TargetFramework> <TargetFramework>netcoreapp1.1</TargetFramework>
<TreatWarningsAsErrors>true</TreatWarningsAsErrors> <TreatWarningsAsErrors>true</TreatWarningsAsErrors>
<AssemblyName>Cap.Consistency.Test</AssemblyName> <AssemblyName>DotNetCore.CAP.Test</AssemblyName>
<PackageId>Cap.Consistency.Test</PackageId> <PackageId>DotNetCore.CAP.Test</PackageId>
<GenerateRuntimeConfigurationFiles>true</GenerateRuntimeConfigurationFiles> <GenerateRuntimeConfigurationFiles>true</GenerateRuntimeConfigurationFiles>
<PackageTargetFallback>$(PackageTargetFallback);dnxcore50;portable-net451+win8</PackageTargetFallback> <PackageTargetFallback>$(PackageTargetFallback);dnxcore50;portable-net451+win8</PackageTargetFallback>
<RuntimeFrameworkVersion>1.1.1</RuntimeFrameworkVersion> <RuntimeFrameworkVersion>1.1.1</RuntimeFrameworkVersion>
...@@ -15,7 +15,7 @@ ...@@ -15,7 +15,7 @@
</ItemGroup> </ItemGroup>
<ItemGroup> <ItemGroup>
<ProjectReference Include="..\..\src\Cap.Consistency\Cap.Consistency.csproj" /> <ProjectReference Include="..\..\src\DotNetCore.CAP\DotNetCore.CAP.csproj" />
</ItemGroup> </ItemGroup>
<ItemGroup> <ItemGroup>
......
//using System; //using System;
//using System.Threading; //using System.Threading;
//using System.Threading.Tasks; //using System.Threading.Tasks;
//using Cap.Consistency.Infrastructure; //using DotNetCore.CAP.Infrastructure;
//using Cap.Consistency.Store; //using DotNetCore.CAP.Store;
//namespace Cap.Consistency.Test //namespace DotNetCore.CAP.Test
//{ //{
// public class NoopMessageStore : IConsistencyMessageStore // public class NoopMessageStore : IConsistencyMessageStore
// { // {
......
using System.Linq; using System.Linq;
using Xunit; using Xunit;
namespace Cap.Consistency.Test namespace DotNetCore.CAP.Test
{ {
public class OperateResultTest public class OperateResultTest
{ {
......
...@@ -4,15 +4,15 @@ ...@@ -4,15 +4,15 @@
//using System.Linq.Expressions; //using System.Linq.Expressions;
//using System.Security.Claims; //using System.Security.Claims;
//using System.Threading.Tasks; //using System.Threading.Tasks;
//using Cap.Consistency.Infrastructure; //using DotNetCore.CAP.Infrastructure;
//using Cap.Consistency.Store; //using DotNetCore.CAP.Store;
//using Microsoft.AspNetCore.Builder; //using Microsoft.AspNetCore.Builder;
//using Microsoft.AspNetCore.Http; //using Microsoft.AspNetCore.Http;
//using Microsoft.Extensions.DependencyInjection; //using Microsoft.Extensions.DependencyInjection;
//using Microsoft.Extensions.Logging; //using Microsoft.Extensions.Logging;
//using Xunit; //using Xunit;
//namespace Cap.Consistency.Test //namespace DotNetCore.CAP.Test
//{ //{
// public abstract class MessageManagerTestBase<TMessage> : MessageManagerTestBase<TMessage, string> // public abstract class MessageManagerTestBase<TMessage> : MessageManagerTestBase<TMessage, string>
// where TMessage : ConsistencyMessage // where TMessage : ConsistencyMessage
......
using System; using System;
using Cap.Consistency.Infrastructure; using DotNetCore.CAP.Infrastructure;
namespace Cap.Consistency.Test namespace DotNetCore.CAP.Test
{ {
} }
...@@ -2,7 +2,7 @@ using System; ...@@ -2,7 +2,7 @@ using System;
using System.Collections.Generic; using System.Collections.Generic;
using Microsoft.Extensions.Logging; using Microsoft.Extensions.Logging;
namespace Cap.Consistency.Test namespace DotNetCore.CAP.Test
{ {
public interface ITestLogger public interface ITestLogger
{ {
......
Markdown is supported
0% or
You are about to add 0 people to the discussion. Proceed with caution.
Finish editing this message first!
Please register or to comment