diff --git a/Masa.Contrib.sln b/Masa.Contrib.sln
index 916526334..8854ccb52 100644
--- a/Masa.Contrib.sln
+++ b/Masa.Contrib.sln
@@ -302,6 +302,11 @@ Project("{2150E333-8FDC-42A3-9474-1A3956D46DE8}") = "BasicAbility", "BasicAbilit
EndProject
Project("{9A19103F-16F7-4668-BE54-9A1E7A4F7556}") = "Masa.BuildingBlocks.BasicAbility.Scheduler", "src\BuildingBlocks\MASA.BuildingBlocks\src\BasicAbility\Masa.BuildingBlocks.BasicAbility.Scheduler\Masa.BuildingBlocks.BasicAbility.Scheduler.csproj", "{0EB0CB69-4C44-4462-A92A-A9B9FDA171DE}"
EndProject
+
+Project("{9A19103F-16F7-4668-BE54-9A1E7A4F7556}") = "Masa.Contrib.BasicAbility.Scheduler.Tests", "test\Masa.Contrib.BasicAbility.Scheduler.Tests\Masa.Contrib.BasicAbility.Scheduler.Tests.csproj", "{5980D054-E2F3-4143-93D1-01993A955AE7}"
+EndProject
+Project("{9A19103F-16F7-4668-BE54-9A1E7A4F7556}") = "Masa.Contrib.BasicAbility.Scheduler", "src\BasicAbility\Masa.Contrib.BasicAbility.Scheduler\Masa.Contrib.BasicAbility.Scheduler.csproj", "{8D84666E-C79E-4D49-B73D-360E62D312EF}"
+EndProject
Global
GlobalSection(SolutionConfigurationPlatforms) = preSolution
Debug|Any CPU = Debug|Any CPU
@@ -1230,6 +1235,38 @@ Global
{789ABED5-7C94-4F6F-ADCA-E97F3DFC9479}.Release|Any CPU.Build.0 = Release|Any CPU
{789ABED5-7C94-4F6F-ADCA-E97F3DFC9479}.Release|x64.ActiveCfg = Release|Any CPU
{789ABED5-7C94-4F6F-ADCA-E97F3DFC9479}.Release|x64.Build.0 = Release|Any CPU
+ {D91C3145-C31C-4301-A493-96F94C903CF2}.Debug|Any CPU.ActiveCfg = Debug|Any CPU
+ {D91C3145-C31C-4301-A493-96F94C903CF2}.Debug|Any CPU.Build.0 = Debug|Any CPU
+ {D91C3145-C31C-4301-A493-96F94C903CF2}.Debug|x64.ActiveCfg = Debug|Any CPU
+ {D91C3145-C31C-4301-A493-96F94C903CF2}.Debug|x64.Build.0 = Debug|Any CPU
+ {D91C3145-C31C-4301-A493-96F94C903CF2}.Release|Any CPU.ActiveCfg = Release|Any CPU
+ {D91C3145-C31C-4301-A493-96F94C903CF2}.Release|Any CPU.Build.0 = Release|Any CPU
+ {D91C3145-C31C-4301-A493-96F94C903CF2}.Release|x64.ActiveCfg = Release|Any CPU
+ {D91C3145-C31C-4301-A493-96F94C903CF2}.Release|x64.Build.0 = Release|Any CPU
+ {FD35BEFA-512C-4483-B5C0-ADCA35680315}.Debug|Any CPU.ActiveCfg = Debug|Any CPU
+ {FD35BEFA-512C-4483-B5C0-ADCA35680315}.Debug|Any CPU.Build.0 = Debug|Any CPU
+ {FD35BEFA-512C-4483-B5C0-ADCA35680315}.Debug|x64.ActiveCfg = Debug|Any CPU
+ {FD35BEFA-512C-4483-B5C0-ADCA35680315}.Debug|x64.Build.0 = Debug|Any CPU
+ {FD35BEFA-512C-4483-B5C0-ADCA35680315}.Release|Any CPU.ActiveCfg = Release|Any CPU
+ {FD35BEFA-512C-4483-B5C0-ADCA35680315}.Release|Any CPU.Build.0 = Release|Any CPU
+ {FD35BEFA-512C-4483-B5C0-ADCA35680315}.Release|x64.ActiveCfg = Release|Any CPU
+ {FD35BEFA-512C-4483-B5C0-ADCA35680315}.Release|x64.Build.0 = Release|Any CPU
+ {5980D054-E2F3-4143-93D1-01993A955AE7}.Debug|Any CPU.ActiveCfg = Debug|Any CPU
+ {5980D054-E2F3-4143-93D1-01993A955AE7}.Debug|Any CPU.Build.0 = Debug|Any CPU
+ {5980D054-E2F3-4143-93D1-01993A955AE7}.Debug|x64.ActiveCfg = Debug|Any CPU
+ {5980D054-E2F3-4143-93D1-01993A955AE7}.Debug|x64.Build.0 = Debug|Any CPU
+ {5980D054-E2F3-4143-93D1-01993A955AE7}.Release|Any CPU.ActiveCfg = Release|Any CPU
+ {5980D054-E2F3-4143-93D1-01993A955AE7}.Release|Any CPU.Build.0 = Release|Any CPU
+ {5980D054-E2F3-4143-93D1-01993A955AE7}.Release|x64.ActiveCfg = Release|Any CPU
+ {5980D054-E2F3-4143-93D1-01993A955AE7}.Release|x64.Build.0 = Release|Any CPU
+ {8D84666E-C79E-4D49-B73D-360E62D312EF}.Debug|Any CPU.ActiveCfg = Debug|Any CPU
+ {8D84666E-C79E-4D49-B73D-360E62D312EF}.Debug|Any CPU.Build.0 = Debug|Any CPU
+ {8D84666E-C79E-4D49-B73D-360E62D312EF}.Debug|x64.ActiveCfg = Debug|Any CPU
+ {8D84666E-C79E-4D49-B73D-360E62D312EF}.Debug|x64.Build.0 = Debug|Any CPU
+ {8D84666E-C79E-4D49-B73D-360E62D312EF}.Release|Any CPU.ActiveCfg = Release|Any CPU
+ {8D84666E-C79E-4D49-B73D-360E62D312EF}.Release|Any CPU.Build.0 = Release|Any CPU
+ {8D84666E-C79E-4D49-B73D-360E62D312EF}.Release|x64.ActiveCfg = Release|Any CPU
+ {8D84666E-C79E-4D49-B73D-360E62D312EF}.Release|x64.Build.0 = Release|Any CPU
{981E883E-CCDC-400B-8FB1-76E1E65C32AF}.Debug|Any CPU.ActiveCfg = Debug|Any CPU
{981E883E-CCDC-400B-8FB1-76E1E65C32AF}.Debug|Any CPU.Build.0 = Debug|Any CPU
{981E883E-CCDC-400B-8FB1-76E1E65C32AF}.Debug|x64.ActiveCfg = Debug|Any CPU
@@ -1393,6 +1430,8 @@ Global
{FF3FD53D-D23E-48AC-98B6-3B028B4DE8AF} = {0D34A7F0-DC77-4789-A136-93089CBD15C3}
{83FA668F-C838-4883-996D-AF2ECF00FDF8} = {5DFAF4A2-ECB5-46E4-904D-1EA5F48B2D48}
{789ABED5-7C94-4F6F-ADCA-E97F3DFC9479} = {38E6C400-90C0-493E-9266-C1602E229F1B}
+ {5980D054-E2F3-4143-93D1-01993A955AE7} = {38E6C400-90C0-493E-9266-C1602E229F1B}
+ {8D84666E-C79E-4D49-B73D-360E62D312EF} = {5DFAF4A2-ECB5-46E4-904D-1EA5F48B2D48}
{981E883E-CCDC-400B-8FB1-76E1E65C32AF} = {0D34A7F0-DC77-4789-A136-93089CBD15C3}
{0D34A7F0-DC77-4789-A136-93089CBD15C3} = {DC578D74-98F0-4F19-A230-CFA8DAEE0AF1}
{0EB0CB69-4C44-4462-A92A-A9B9FDA171DE} = {0D34A7F0-DC77-4789-A136-93089CBD15C3}
diff --git a/src/BasicAbility/Masa.Contrib.BasicAbility.Scheduler/Constants.cs b/src/BasicAbility/Masa.Contrib.BasicAbility.Scheduler/Constants.cs
new file mode 100644
index 000000000..de50d9580
--- /dev/null
+++ b/src/BasicAbility/Masa.Contrib.BasicAbility.Scheduler/Constants.cs
@@ -0,0 +1,10 @@
+// Copyright (c) MASA Stack All rights reserved.
+// Licensed under the MIT License. See LICENSE.txt in the project root for license information.
+
+namespace Masa.Contrib.BasicAbility.Scheduler;
+
+internal class Constants
+{
+ internal const string DEFAULT_CLIENT_NAME = "masa.contrib.basicability.scheduler";
+ internal const string ENVIRONMENT_KEY = "env_key";
+}
diff --git a/src/BasicAbility/Masa.Contrib.BasicAbility.Scheduler/Masa.Contrib.BasicAbility.Scheduler.csproj b/src/BasicAbility/Masa.Contrib.BasicAbility.Scheduler/Masa.Contrib.BasicAbility.Scheduler.csproj
new file mode 100644
index 000000000..013e83a80
--- /dev/null
+++ b/src/BasicAbility/Masa.Contrib.BasicAbility.Scheduler/Masa.Contrib.BasicAbility.Scheduler.csproj
@@ -0,0 +1,18 @@
+
+
+
+ net6.0
+ enable
+ enable
+
+
+
+
+
+
+
+
+
+
+
+
diff --git a/src/BasicAbility/Masa.Contrib.BasicAbility.Scheduler/SchedulerClient.cs b/src/BasicAbility/Masa.Contrib.BasicAbility.Scheduler/SchedulerClient.cs
new file mode 100644
index 000000000..658cc2755
--- /dev/null
+++ b/src/BasicAbility/Masa.Contrib.BasicAbility.Scheduler/SchedulerClient.cs
@@ -0,0 +1,17 @@
+// Copyright (c) MASA Stack All rights reserved.
+// Licensed under the MIT License. See LICENSE.txt in the project root for license information.
+
+namespace Masa.Contrib.BasicAbility.Scheduler;
+
+public class SchedulerClient : ISchedulerClient
+{
+ public ISchedulerJobService SchedulerJobService { get; }
+
+ public ISchedulerTaskService SchedulerTaskService { get; }
+
+ public SchedulerClient(ICallerProvider callerProvider, ILoggerFactory? loggerFactory = null)
+ {
+ SchedulerJobService = new SchedulerJobService(callerProvider, loggerFactory);
+ SchedulerTaskService = new SchedulerTaskService(callerProvider, loggerFactory);
+ }
+}
diff --git a/src/BasicAbility/Masa.Contrib.BasicAbility.Scheduler/ServiceCollectionExtensions.cs b/src/BasicAbility/Masa.Contrib.BasicAbility.Scheduler/ServiceCollectionExtensions.cs
new file mode 100644
index 000000000..813475a11
--- /dev/null
+++ b/src/BasicAbility/Masa.Contrib.BasicAbility.Scheduler/ServiceCollectionExtensions.cs
@@ -0,0 +1,51 @@
+// Copyright (c) MASA Stack All rights reserved.
+// Licensed under the MIT License. See LICENSE.txt in the project root for license information.
+
+namespace Microsoft.Extensions.DependencyInjection;
+
+public static class ServiceCollectionExtensions
+{
+ public static IServiceCollection AddSchedulerClient(this IServiceCollection services, string schedulerServiceBaseAddress)
+ {
+ if (string.IsNullOrWhiteSpace(schedulerServiceBaseAddress))
+ {
+ throw new ArgumentNullException(nameof(schedulerServiceBaseAddress));
+ }
+
+ services.AddSingleton();
+ return services.AddSchedulerClient(callerOptions =>
+ {
+ callerOptions.UseHttpClient(builder =>
+ {
+ builder.Name = DEFAULT_CLIENT_NAME;
+ builder.Configure = opt => opt.BaseAddress = new Uri(schedulerServiceBaseAddress);
+ });
+ });
+ }
+
+ public static IServiceCollection AddSchedulerClient(this IServiceCollection services, Action callerOptions)
+ {
+ ArgumentNullException.ThrowIfNull(callerOptions, nameof(callerOptions));
+
+ if (services.Any(service => service.ImplementationType == typeof(SchedulerProvider)))
+ return services;
+
+ services.AddSingleton();
+ services.AddHttpContextAccessor();
+ services.AddCaller(callerOptions);
+
+ services.AddScoped(serviceProvider =>
+ {
+ var callProvider = serviceProvider.GetRequiredService().CreateClient(DEFAULT_CLIENT_NAME);
+ var loggerFactory = serviceProvider.GetService();
+ var schedulerClient = new SchedulerClient(callProvider, loggerFactory);
+ return schedulerClient;
+ });
+
+ return services;
+ }
+
+ private class SchedulerProvider
+ {
+ }
+}
diff --git a/src/BasicAbility/Masa.Contrib.BasicAbility.Scheduler/Services/SchedulerJobService.cs b/src/BasicAbility/Masa.Contrib.BasicAbility.Scheduler/Services/SchedulerJobService.cs
new file mode 100644
index 000000000..2c194bc34
--- /dev/null
+++ b/src/BasicAbility/Masa.Contrib.BasicAbility.Scheduler/Services/SchedulerJobService.cs
@@ -0,0 +1,123 @@
+// Copyright (c) MASA Stack All rights reserved.
+// Licensed under the MIT License. See LICENSE.txt in the project root for license information.
+
+namespace Masa.Contrib.BasicAbility.Scheduler.Services;
+
+public class SchedulerJobService : ISchedulerJobService
+{
+ const string API = "/api/scheduler-job";
+
+ readonly ICallerProvider _callerProvider;
+ readonly ILogger? _logger;
+
+ public SchedulerJobService(ICallerProvider callerProvider, ILoggerFactory? loggerFactory = null)
+ {
+ _callerProvider = callerProvider;
+ _logger = loggerFactory?.CreateLogger();
+ }
+
+ public async Task AddbAsync(AddSchedulerJobRequest request)
+ {
+ if (string.IsNullOrWhiteSpace(request.ProjectIdentity))
+ {
+ throw new ArgumentNullException(nameof(request.ProjectIdentity));
+ }
+
+ switch (request.JobType)
+ {
+ case BuildingBlocks.BasicAbility.Scheduler.Enum.JobTypes.JobApp:
+ ArgumentNullException.ThrowIfNull(request.JobAppConfig, nameof(request.JobAppConfig));
+ break;
+ case BuildingBlocks.BasicAbility.Scheduler.Enum.JobTypes.Http:
+ ArgumentNullException.ThrowIfNull(request.HttpConfig, nameof(request.HttpConfig));
+ break;
+ case BuildingBlocks.BasicAbility.Scheduler.Enum.JobTypes.DaprServiceInvocation:
+ ArgumentNullException.ThrowIfNull(request.DaprServiceInvocationConfig, nameof(request.DaprServiceInvocationConfig));
+ break;
+ }
+
+ try
+ {
+ var requestUri = $"{API}/addSchedulerJobBySdk";
+ return await _callerProvider.PostAsync(requestUri, request);
+ }
+ catch (Exception ex)
+ {
+ _logger?.LogError(ex, "AddSchedulerJobAsync Error");
+ return Guid.Empty;
+ }
+
+ }
+
+ public async Task DisableAsync(BaseSchedulerJobRequest request)
+ {
+ try
+ {
+ var requestData = new ChangeEnabledStatusRequest()
+ {
+ JobId = request.JobId,
+ OperatorId = request.OperatorId,
+ Enabled = false
+ };
+ var requestUri = $"{API}/changeEnableStatus";
+ await _callerProvider.PutAsync(requestUri, requestData);
+ return true;
+ }
+ catch (Exception ex)
+ {
+ _logger?.LogError(ex, "DisableSchedulerJob Error");
+ return false;
+ }
+ }
+
+ public async Task EnableAsync(BaseSchedulerJobRequest request)
+ {
+ try
+ {
+ var requestData = new ChangeEnabledStatusRequest()
+ {
+ JobId = request.JobId,
+ OperatorId = request.OperatorId,
+ Enabled = true
+ };
+ var requestUri = $"{API}/changeEnableStatus";
+ await _callerProvider.PutAsync(requestUri, requestData);
+ return true;
+ }
+ catch (Exception ex)
+ {
+ _logger?.LogError(ex, "EnableSchedulerJob Error");
+ return false;
+ }
+ }
+
+ public async Task RemoveAsync(BaseSchedulerJobRequest request)
+ {
+ try
+ {
+ var requestUri = $"{API}";
+ await _callerProvider.DeleteAsync(requestUri, request);
+ return true;
+ }
+ catch (Exception ex)
+ {
+ _logger?.LogError(ex, "RemoveSchedulerJobAsync Error");
+ return false;
+ }
+ }
+
+ public async Task StartAsync(BaseSchedulerJobRequest request)
+ {
+ try
+ {
+ var requestUri = $"{API}/startJob";
+ await _callerProvider.PutAsync(requestUri, request);
+ return true;
+ }
+ catch (Exception ex)
+ {
+ _logger?.LogError(ex, "StartSchedulerJobAsync Error");
+ return false;
+ }
+ }
+}
diff --git a/src/BasicAbility/Masa.Contrib.BasicAbility.Scheduler/Services/SchedulerTaskService.cs b/src/BasicAbility/Masa.Contrib.BasicAbility.Scheduler/Services/SchedulerTaskService.cs
new file mode 100644
index 000000000..29806b4d5
--- /dev/null
+++ b/src/BasicAbility/Masa.Contrib.BasicAbility.Scheduler/Services/SchedulerTaskService.cs
@@ -0,0 +1,55 @@
+// Copyright (c) MASA Stack All rights reserved.
+// Licensed under the MIT License. See LICENSE.txt in the project root for license information.
+
+namespace Masa.Contrib.BasicAbility.Scheduler.Services;
+
+public class SchedulerTaskService : ISchedulerTaskService
+{
+ const string API = "/api/scheduler-task";
+
+ readonly ICallerProvider _callerProvider;
+ readonly ILogger? _logger;
+
+ public SchedulerTaskService(ICallerProvider callerProvider, ILoggerFactory? loggerFactory)
+ {
+ _callerProvider = callerProvider;
+ _logger = loggerFactory?.CreateLogger();
+ }
+
+ public async Task StopAsync(BaseSchedulerTaskRequest request)
+ {
+ try
+ {
+ var requestUri = $"{API}/stop";
+ await _callerProvider.PutAsync(requestUri, request);
+ return true;
+ }
+ catch (Exception ex)
+ {
+ _logger?.LogError(ex, "StopSchedulerTaskAsync Error");
+ return false;
+ }
+ }
+
+ public async Task StartAsync(BaseSchedulerTaskRequest request)
+ {
+ try
+ {
+ var requestData = new StartSchedulerTaskRequest()
+ {
+ TaskId = request.TaskId,
+ OperatorId = request.OperatorId,
+ IsManual = true
+ };
+
+ var requestUri = $"{API}/start";
+ await _callerProvider.PutAsync(requestUri, requestData);
+ return true;
+ }
+ catch (Exception ex)
+ {
+ _logger?.LogError(ex, "StopSchedulerTaskAsync Error");
+ return false;
+ }
+ }
+}
diff --git a/src/BasicAbility/Masa.Contrib.BasicAbility.Scheduler/_Imports.cs b/src/BasicAbility/Masa.Contrib.BasicAbility.Scheduler/_Imports.cs
new file mode 100644
index 000000000..cb3f0e0ed
--- /dev/null
+++ b/src/BasicAbility/Masa.Contrib.BasicAbility.Scheduler/_Imports.cs
@@ -0,0 +1,13 @@
+// Copyright (c) MASA Stack All rights reserved.
+// Licensed under the MIT License. See LICENSE.txt in the project root for license information.
+
+global using Masa.BuildingBlocks.BasicAbility.Scheduler;
+global using Masa.BuildingBlocks.BasicAbility.Scheduler.Request;
+global using Masa.BuildingBlocks.BasicAbility.Scheduler.Service;
+global using Masa.BuildingBlocks.Identity.IdentityModel;
+global using Masa.Contrib.BasicAbility.Scheduler;
+global using Masa.Contrib.BasicAbility.Scheduler.Services;
+global using Masa.Utils.Caller.Core;
+global using Masa.Utils.Caller.HttpClient;
+global using Microsoft.Extensions.Logging;
+global using static Masa.Contrib.BasicAbility.Scheduler.Constants;
diff --git a/src/BuildingBlocks/MASA.BuildingBlocks b/src/BuildingBlocks/MASA.BuildingBlocks
index 61fe682cc..c19f0f87f 160000
--- a/src/BuildingBlocks/MASA.BuildingBlocks
+++ b/src/BuildingBlocks/MASA.BuildingBlocks
@@ -1 +1 @@
-Subproject commit 61fe682cc794cc826d7301800043e037b14d0e6a
+Subproject commit c19f0f87fb185a12bae9b238f82d68c4f91cdb02
diff --git a/test/Masa.Contrib.BasicAbility.Scheduler.Tests/Masa.Contrib.BasicAbility.Scheduler.Tests.csproj b/test/Masa.Contrib.BasicAbility.Scheduler.Tests/Masa.Contrib.BasicAbility.Scheduler.Tests.csproj
new file mode 100644
index 000000000..01624c4f7
--- /dev/null
+++ b/test/Masa.Contrib.BasicAbility.Scheduler.Tests/Masa.Contrib.BasicAbility.Scheduler.Tests.csproj
@@ -0,0 +1,26 @@
+
+
+
+ net6.0
+ enable
+
+ false
+
+
+
+
+
+
+
+
+ all
+ runtime; build; native; contentfiles; analyzers; buildtransitive
+
+
+
+
+
+
+
+
+
diff --git a/test/Masa.Contrib.BasicAbility.Scheduler.Tests/SchedulerClientTest.cs b/test/Masa.Contrib.BasicAbility.Scheduler.Tests/SchedulerClientTest.cs
new file mode 100644
index 000000000..46959a645
--- /dev/null
+++ b/test/Masa.Contrib.BasicAbility.Scheduler.Tests/SchedulerClientTest.cs
@@ -0,0 +1,52 @@
+// Copyright (c) MASA Stack All rights reserved.
+// Licensed under the MIT License. See LICENSE.txt in the project root for license information.
+
+namespace Masa.Contrib.BasicAbility.Scheduler.Tests;
+
+[TestClass]
+public class SchedulerClientTest
+{
+ [TestMethod]
+ public void TestAddSchedulerClientByOptions()
+ {
+ var services = new ServiceCollection();
+
+ services.AddSchedulerClient(option =>
+ {
+ option.UseHttpClient(builder =>
+ {
+ builder.Name = "masa.contrib.basicability.scheduler";
+ builder.Configure = opt => opt.BaseAddress = new Uri("https://github.com");
+ });
+ });
+
+ var schedulerClient = services.BuildServiceProvider().GetService();
+ Assert.IsNotNull(schedulerClient);
+ }
+
+ [TestMethod]
+ public void TestAddSchedulerClient()
+ {
+ var services = new ServiceCollection();
+ services.AddSchedulerClient("https://github.com");
+ var schedulerClient = services.BuildServiceProvider().GetService();
+ Assert.IsNotNull(schedulerClient);
+ }
+
+ [TestMethod]
+ public void TestAddSchedulerClientShouldThrowArgumentNullException()
+ {
+ var services = new ServiceCollection();
+
+ Assert.ThrowsException(() => services.AddSchedulerClient(""));
+ }
+
+ [TestMethod]
+ public void TestAddSchedulerClientShouldThrowArgumentNullException2()
+ {
+ var services = new ServiceCollection();
+
+ Assert.ThrowsException(() => services.AddSchedulerClient(callerOptions: null!));
+ }
+
+}
diff --git a/test/Masa.Contrib.BasicAbility.Scheduler.Tests/SchedulerJobServiceTest.cs b/test/Masa.Contrib.BasicAbility.Scheduler.Tests/SchedulerJobServiceTest.cs
new file mode 100644
index 000000000..26720937a
--- /dev/null
+++ b/test/Masa.Contrib.BasicAbility.Scheduler.Tests/SchedulerJobServiceTest.cs
@@ -0,0 +1,302 @@
+// Copyright (c) MASA Stack All rights reserved.
+// Licensed under the MIT License. See LICENSE.txt in the project root for license information.
+
+namespace Masa.Contrib.BasicAbility.Scheduler.Tests;
+
+[TestClass]
+public class SchedulerJobServiceTest
+{
+ const string API = "/api/scheduler-job";
+
+ [TestMethod]
+ public async Task TestAddSchedulerHttpJobAsync()
+ {
+ var requestData = new AddSchedulerJobRequest()
+ {
+ Name = "TestJob",
+ JobType = JobTypes.Http,
+ ProjectIdentity = "MASA_MC",
+ CronExpression = "",
+ HttpConfig = new SchedulerJobHttpConfig()
+ {
+ RequestUrl = "www.baidu.com",
+ HttpVerifyType = HttpVerifyTypes.CustomStatusCode,
+ HttpBody = "",
+ HttpHeaders = new List>()
+ {
+ new KeyValuePair("User-Agent", "Mozilla/5.0 (Windows NT 10.0; Win64; x64) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/102.0.0.0 Safari/537.36")
+ },
+ HttpMethod = HttpMethods.GET,
+ VerifyContent = "200",
+ HttpParameters = new List>()
+ {
+ new KeyValuePair("ie", "utf-8"),
+ }
+ },
+ OperatorId = Guid.NewGuid(),
+ Description = "Test",
+ FailedRetryCount = 0,
+ FailedRetryInterval = 0,
+ IsAlertException = false,
+ RunTimeoutSecond = 30,
+ RunTimeoutStrategy = RunTimeoutStrategyTypes.IgnoreTimeout,
+ ScheduleBlockStrategy = ScheduleBlockStrategyTypes.Parallel,
+ ScheduleExpiredStrategy = ScheduleExpiredStrategyTypes.Ignore
+ };
+
+ var requestUri = $"{API}/addSchedulerJobBySdk";
+ var callerProvider = new Mock();
+ var loggerFactory = new Mock();
+ callerProvider.Setup(provider => provider.PostAsync(requestUri, requestData, default)).ReturnsAsync(Guid.NewGuid()).Verifiable();
+ var schedulerClient = new SchedulerClient(callerProvider.Object, loggerFactory.Object);
+ var result = await schedulerClient.SchedulerJobService.AddbAsync(requestData);
+ callerProvider.Verify(provider => provider.PostAsync(requestUri, requestData, default), Times.Once);
+
+ Assert.AreNotEqual(Guid.Empty, result);
+ }
+
+ [TestMethod]
+ public async Task TestAddSchedulerJobApp()
+ {
+ var requestData = new AddSchedulerJobRequest()
+ {
+ Name = "TestJob",
+ JobType = JobTypes.JobApp,
+ ProjectIdentity = "MASA_MC",
+ CronExpression = "",
+ JobAppConfig = new SchedulerJobAppConfig()
+ {
+ JobAppIdentity = "MASA_MC_SERVICE",
+ JobEntryAssembly = "Masa.Test.Job",
+ JobEntryMethod = "TestRunJob",
+ JobParams = "1;2;3",
+ Version = ""
+ },
+ OperatorId = Guid.NewGuid(),
+ Description = "Test",
+ FailedRetryCount = 0,
+ FailedRetryInterval = 0,
+ IsAlertException = false,
+ RunTimeoutSecond = 30,
+ RunTimeoutStrategy = RunTimeoutStrategyTypes.IgnoreTimeout,
+ ScheduleBlockStrategy = ScheduleBlockStrategyTypes.Parallel,
+ ScheduleExpiredStrategy = ScheduleExpiredStrategyTypes.Ignore
+ };
+
+ var requestUri = $"{API}/addSchedulerJobBySdk";
+ var callerProvider = new Mock();
+ var loggerFactory = new Mock();
+ callerProvider.Setup(provider => provider.PostAsync(requestUri, requestData, default)).ReturnsAsync(Guid.NewGuid()).Verifiable();
+ var schedulerClient = new SchedulerClient(callerProvider.Object, loggerFactory.Object);
+ var result = await schedulerClient.SchedulerJobService.AddbAsync(requestData);
+ callerProvider.Verify(provider => provider.PostAsync(requestUri, requestData, default), Times.Once);
+
+ Assert.AreNotEqual(Guid.Empty, result);
+ }
+
+ [TestMethod]
+ public async Task TestAddSchedulerDaprServiceInvocationJob()
+ {
+ var requestData = new AddSchedulerJobRequest()
+ {
+ Name = "TestJob",
+ JobType = JobTypes.DaprServiceInvocation,
+ ProjectIdentity = "MASA_MC",
+ CronExpression = "",
+ DaprServiceInvocationConfig = new SchedulerJobDaprServiceInvocationConfig()
+ {
+ DaprServiceIdentity = "MASA_MC_DAPR_SERVICE",
+ Data = "Test",
+ HttpMethod = HttpMethods.POST,
+ MethodName = "TestMethod"
+ },
+ OperatorId = Guid.NewGuid(),
+ Description = "Test",
+ FailedRetryCount = 0,
+ FailedRetryInterval = 0,
+ IsAlertException = false,
+ RunTimeoutSecond = 30,
+ RunTimeoutStrategy = RunTimeoutStrategyTypes.IgnoreTimeout,
+ ScheduleBlockStrategy = ScheduleBlockStrategyTypes.Parallel,
+ ScheduleExpiredStrategy = ScheduleExpiredStrategyTypes.Ignore
+ };
+
+ var requestUri = $"{API}/addSchedulerJobBySdk";
+ var callerProvider = new Mock();
+ var loggerFactory = new Mock();
+ callerProvider.Setup(provider => provider.PostAsync(requestUri, requestData, default)).ReturnsAsync(Guid.NewGuid()).Verifiable();
+ var schedulerClient = new SchedulerClient(callerProvider.Object, loggerFactory.Object);
+ var result = await schedulerClient.SchedulerJobService.AddbAsync(requestData);
+ callerProvider.Verify(provider => provider.PostAsync(requestUri, requestData, default), Times.Once);
+
+ Assert.AreNotEqual(Guid.Empty, result);
+ }
+
+ [TestMethod]
+ public async Task TestAddSchedulerJobArgumentNullException()
+ {
+ var requestData = new AddSchedulerJobRequest()
+ {
+ Name = "TestJob",
+ JobType = JobTypes.Http,
+ CronExpression = "",
+ HttpConfig = new SchedulerJobHttpConfig()
+ {
+ RequestUrl = "www.baidu.com",
+ HttpVerifyType = HttpVerifyTypes.CustomStatusCode,
+ HttpBody = "",
+ HttpHeaders = new List>()
+ {
+ new KeyValuePair("User-Agent", "Mozilla/5.0 (Windows NT 10.0; Win64; x64) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/102.0.0.0 Safari/537.36")
+ },
+ HttpMethod = HttpMethods.GET,
+ VerifyContent = "200",
+ HttpParameters = new List>()
+ {
+ new KeyValuePair("ie", "utf-8"),
+ }
+ },
+ OperatorId = Guid.NewGuid()
+ };
+
+ var requestUri = $"{API}/addSchedulerJobBySdk";
+ var callerProvider = new Mock();
+ var loggerFactory = new Mock();
+ callerProvider.Setup(provider => provider.PostAsync(requestUri, requestData, default)).ReturnsAsync(Guid.NewGuid()).Verifiable();
+ var schedulerClient = new SchedulerClient(callerProvider.Object, loggerFactory.Object);
+ await Assert.ThrowsExceptionAsync(async () => await schedulerClient.SchedulerJobService.AddbAsync(requestData));
+ }
+
+ [TestMethod]
+ public async Task TestAddSchedulerHttpJobArgumentNullException()
+ {
+ var requestData = new AddSchedulerJobRequest()
+ {
+ Name = "TestJob",
+ JobType = JobTypes.Http,
+ CronExpression = "",
+ OperatorId = Guid.NewGuid()
+ };
+
+ var requestUri = $"{API}/addSchedulerJobBySdk";
+ var callerProvider = new Mock();
+ var loggerFactory = new Mock();
+ callerProvider.Setup(provider => provider.PostAsync(requestUri, requestData, default)).ReturnsAsync(Guid.NewGuid()).Verifiable();
+ var schedulerClient = new SchedulerClient(callerProvider.Object, loggerFactory.Object);
+ await Assert.ThrowsExceptionAsync(async () => await schedulerClient.SchedulerJobService.AddbAsync(requestData));
+ }
+
+ [TestMethod]
+ public async Task TestAddSchedulerJobAppArgumentNullException()
+ {
+ var requestData = new AddSchedulerJobRequest()
+ {
+ Name = "TestJob",
+ JobType = JobTypes.JobApp,
+ CronExpression = "",
+ OperatorId = Guid.NewGuid()
+ };
+
+ var requestUri = $"{API}/addSchedulerJobBySdk";
+ var callerProvider = new Mock();
+ var loggerFactory = new Mock();
+ callerProvider.Setup(provider => provider.PostAsync(requestUri, requestData, default)).ReturnsAsync(Guid.NewGuid()).Verifiable();
+ var schedulerClient = new SchedulerClient(callerProvider.Object, loggerFactory.Object);
+ await Assert.ThrowsExceptionAsync(async () => await schedulerClient.SchedulerJobService.AddbAsync(requestData));
+ }
+
+ [TestMethod]
+ public async Task TestAddSchedulerDaprInvocationJobArgumentNullException()
+ {
+ var requestData = new AddSchedulerJobRequest()
+ {
+ Name = "TestJob",
+ JobType = JobTypes.DaprServiceInvocation,
+ CronExpression = "",
+ OperatorId = Guid.NewGuid()
+ };
+
+ var requestUri = $"{API}/addSchedulerJobBySdk";
+ var callerProvider = new Mock();
+ var loggerFactory = new Mock();
+ callerProvider.Setup(provider => provider.PostAsync(requestUri, requestData, default)).ReturnsAsync(Guid.NewGuid()).Verifiable();
+ var schedulerClient = new SchedulerClient(callerProvider.Object, loggerFactory.Object);
+ await Assert.ThrowsExceptionAsync(async () => await schedulerClient.SchedulerJobService.AddbAsync(requestData));
+ }
+
+ [TestMethod]
+ public async Task TestRemoveSchedulerJobAsync()
+ {
+ var requestData = new BaseSchedulerJobRequest()
+ {
+ JobId = Guid.NewGuid(),
+ OperatorId = Guid.NewGuid()
+ };
+
+ var callerProvider = new Mock();
+ var loggerFactory = new Mock();
+ callerProvider.Setup(provider => provider.DeleteAsync(API, requestData, true, default)).Verifiable();
+ var schedulerClient = new SchedulerClient(callerProvider.Object, loggerFactory.Object);
+ var result = await schedulerClient.SchedulerJobService.RemoveAsync(requestData);
+ callerProvider.Verify(provider => provider.DeleteAsync(API, requestData, true, default), Times.Once);
+
+ Assert.IsTrue(result);
+ }
+
+ [TestMethod]
+ public async Task TestStartSchedulerJobAsync()
+ {
+ var requestData = new BaseSchedulerJobRequest()
+ {
+ JobId = Guid.NewGuid(),
+ OperatorId = Guid.NewGuid()
+ };
+
+ var requestUri = $"{API}/startJob";
+ var callerProvider = new Mock();
+ var loggerFactory = new Mock();
+ callerProvider.Setup(provider => provider.PutAsync(requestUri, requestData, true, default)).Verifiable();
+ var schedulerClient = new SchedulerClient(callerProvider.Object, loggerFactory.Object);
+ var result = await schedulerClient.SchedulerJobService.StartAsync(requestData);
+ callerProvider.Verify(provider => provider.PutAsync(requestUri, requestData, true, default), Times.Once);
+ Assert.IsTrue(result);
+ }
+
+ [TestMethod]
+ public async Task TestEnableSchedulerJob()
+ {
+ var requestData = new BaseSchedulerJobRequest()
+ {
+ JobId = Guid.NewGuid(),
+ OperatorId = Guid.NewGuid()
+ };
+
+ var requestUri = $"{API}/changeEnableStatus";
+ var callerProvider = new Mock();
+ var loggerFactory = new Mock();
+ callerProvider.Setup(provider => provider.PutAsync(requestUri, It.IsAny(), true, default)).Verifiable();
+ var schedulerClient = new SchedulerClient(callerProvider.Object, loggerFactory.Object);
+ var result = await schedulerClient.SchedulerJobService.EnableAsync(requestData);
+ callerProvider.Verify(provider => provider.PutAsync(requestUri, It.IsAny(), true, default), Times.Once);
+ Assert.IsTrue(result);
+ }
+
+ [TestMethod]
+ public async Task TestDisableSchedulerJob()
+ {
+ var requestData = new BaseSchedulerJobRequest()
+ {
+ JobId = Guid.NewGuid(),
+ OperatorId = Guid.NewGuid()
+ };
+
+ var requestUri = $"{API}/changeEnableStatus";
+ var callerProvider = new Mock();
+ var loggerFactory = new Mock();
+ callerProvider.Setup(provider => provider.PutAsync(requestUri, It.IsAny(), true, default)).Verifiable();
+ var schedulerClient = new SchedulerClient(callerProvider.Object, loggerFactory.Object);
+ var result = await schedulerClient.SchedulerJobService.DisableAsync(requestData);
+ callerProvider.Verify(provider => provider.PutAsync(requestUri, It.IsAny(), true, default), Times.Once);
+ Assert.IsTrue(result);
+ }
+}
diff --git a/test/Masa.Contrib.BasicAbility.Scheduler.Tests/SchedulerTaskServiceTest.cs b/test/Masa.Contrib.BasicAbility.Scheduler.Tests/SchedulerTaskServiceTest.cs
new file mode 100644
index 000000000..a18086153
--- /dev/null
+++ b/test/Masa.Contrib.BasicAbility.Scheduler.Tests/SchedulerTaskServiceTest.cs
@@ -0,0 +1,48 @@
+// Copyright (c) MASA Stack All rights reserved.
+// Licensed under the MIT License. See LICENSE.txt in the project root for license information.
+
+namespace Masa.Contrib.BasicAbility.Scheduler.Tests;
+
+[TestClass]
+public class SchedulerTaskServiceTest
+{
+ const string API = "/api/scheduler-task";
+
+ [TestMethod]
+ public async Task TestStopSchedulerTaskAsync()
+ {
+ var requestData = new BaseSchedulerTaskRequest()
+ {
+ TaskId = Guid.NewGuid(),
+ OperatorId = Guid.NewGuid()
+ };
+
+ var requestUri = $"{API}/stop";
+ var callerProvider = new Mock();
+ var loggerFactory = new Mock();
+ callerProvider.Setup(provider => provider.PutAsync(requestUri, requestData, true, default)).Verifiable();
+ var schedulerClient = new SchedulerClient(callerProvider.Object, loggerFactory.Object);
+ var result = await schedulerClient.SchedulerTaskService.StopAsync(requestData);
+ callerProvider.Verify(provider => provider.PutAsync(requestUri, requestData, true, default), Times.Once);
+ Assert.IsTrue(result);
+ }
+
+ [TestMethod]
+ public async Task TestStartSchedulerTaskAsync()
+ {
+ var request = new BaseSchedulerTaskRequest()
+ {
+ TaskId = Guid.NewGuid(),
+ OperatorId = Guid.NewGuid()
+ };
+
+ var requestUri = $"{API}/start";
+ var callerProvider = new Mock();
+ var loggerFactory = new Mock();
+ callerProvider.Setup(provider => provider.PutAsync(requestUri, It.IsAny(), true, default)).Verifiable();
+ var schedulerClient = new SchedulerClient(callerProvider.Object, loggerFactory.Object);
+ var result = await schedulerClient.SchedulerTaskService.StartAsync(request);
+ callerProvider.Verify(provider => provider.PutAsync(requestUri, It.IsAny(), true, default), Times.Once);
+ Assert.IsTrue(result);
+ }
+}
diff --git a/test/Masa.Contrib.BasicAbility.Scheduler.Tests/_Imports.cs b/test/Masa.Contrib.BasicAbility.Scheduler.Tests/_Imports.cs
new file mode 100644
index 000000000..a2ca75efd
--- /dev/null
+++ b/test/Masa.Contrib.BasicAbility.Scheduler.Tests/_Imports.cs
@@ -0,0 +1,16 @@
+// Copyright (c) MASA Stack All rights reserved.
+// Licensed under the MIT License. See LICENSE.txt in the project root for license information.
+
+global using Masa.BuildingBlocks.BasicAbility.Scheduler;
+global using Masa.BuildingBlocks.BasicAbility.Scheduler.Enum;
+global using Masa.BuildingBlocks.BasicAbility.Scheduler.Model;
+global using Masa.BuildingBlocks.BasicAbility.Scheduler.Request;
+global using Masa.Utils.Caller.Core;
+global using Masa.Utils.Caller.HttpClient;
+global using Microsoft.Extensions.DependencyInjection;
+global using Microsoft.Extensions.Logging;
+global using Microsoft.VisualStudio.TestTools.UnitTesting;
+global using Moq;
+global using System;
+global using System.Collections.Generic;
+global using System.Threading.Tasks;