Browse Source

Merge pull request #475 from colinin/scope-job

tasks: use scope services to perform jobs
pull/489/head
yx lin 4 years ago
committed by GitHub
parent
commit
2415c4041b
No known key found for this signature in database GPG Key ID: 4AEE18F83AFDEB23
  1. 15
      apps/vue/src/views/task-management/background-jobs/components/BackgroundJobInfoModal.vue
  2. 75
      aspnet-core/modules/task-management/LINGYUN.Abp.BackgroundTasks.Jobs/LINGYUN/Abp/BackgroundTasks/Jobs/HttpRequestJob.cs
  3. 207
      aspnet-core/modules/task-management/LINGYUN.Abp.BackgroundTasks.Jobs/LINGYUN/Abp/BackgroundTasks/Jobs/HttpRequestJobBase.cs
  4. 18
      aspnet-core/modules/task-management/LINGYUN.Abp.BackgroundTasks.Quartz/LINGYUN/Abp/BackgroundTasks/Quartz/QuartzJobListener.cs
  5. 14
      aspnet-core/modules/task-management/LINGYUN.Abp.BackgroundTasks.Quartz/LINGYUN/Abp/BackgroundTasks/Quartz/QuartzJobSimpleAdapter.cs
  6. 2
      aspnet-core/modules/task-management/LINGYUN.Abp.BackgroundTasks/LINGYUN/Abp/BackgroundTasks/BackgroundJobAdapter.cs
  7. 4
      aspnet-core/modules/task-management/LINGYUN.Abp.BackgroundTasks/LINGYUN/Abp/BackgroundTasks/BackgroundWorkerAdapter.cs
  8. 10
      aspnet-core/modules/task-management/LINGYUN.Abp.BackgroundTasks/LINGYUN/Abp/BackgroundTasks/BackgroundWorkerManager.cs
  9. 2
      aspnet-core/modules/task-management/LINGYUN.Abp.BackgroundTasks/LINGYUN/Abp/BackgroundTasks/Internal/JobExecutedEvent.cs
  10. 6
      aspnet-core/modules/task-management/LINGYUN.Abp.TaskManagement.Application/LINGYUN/Abp/TaskManagement/BackgroundJobInfoAppService.cs
  11. 1
      aspnet-core/modules/task-management/LINGYUN.Abp.TaskManagement.Domain.Shared/LINGYUN/Abp/TaskManagement/Localization/Resources/en.json
  12. 1
      aspnet-core/modules/task-management/LINGYUN.Abp.TaskManagement.Domain.Shared/LINGYUN/Abp/TaskManagement/Localization/Resources/zh-Hans.json
  13. 2
      aspnet-core/modules/task-management/LINGYUN.Abp.TaskManagement.Domain/LINGYUN/Abp/TaskManagement/BackgroundJobInfo.cs

15
apps/vue/src/views/task-management/background-jobs/components/BackgroundJobInfoModal.vue

@ -152,6 +152,13 @@
labelAlign: 'left', labelAlign: 'left',
labelWidth: 120, labelWidth: 120,
schemas: [ schemas: [
{
field: 'oldKey',
component: 'Input',
label: 'oldKey',
show: false,
colProps: { span: 24 },
},
{ {
field: 'key', field: 'key',
component: 'Input', component: 'Input',
@ -319,8 +326,12 @@
function handleSaveParam() { function handleSaveParam() {
validate().then((input) => { validate().then((input) => {
console.log(input);
const model = unref(modelRef); const model = unref(modelRef);
model.args ??= {}; model.args ??= {};
if (input.oldKey && input.key !== input.oldKey) {
delete model.args[input.oldKey];
}
model.args[input.key] = input.value; model.args[input.key] = input.value;
resetParamFields(); resetParamFields();
closeParamModal(); closeParamModal();
@ -330,13 +341,13 @@
function handleEditParam(record) { function handleEditParam(record) {
openParamModal(true); openParamModal(true);
nextTick(() => { nextTick(() => {
setParamFields(record); setParamFields(Object.assign({ oldKey: record.key }, record));
}); });
} }
function handleDeleteParam(record) { function handleDeleteParam(record) {
const model = unref(modelRef); const model = unref(modelRef);
model.args ??= {}; model.args ??= {};
delete model.args[record.key] delete model.args[record.key];
} }
</script> </script>

75
aspnet-core/modules/task-management/LINGYUN.Abp.BackgroundTasks.Jobs/LINGYUN/Abp/BackgroundTasks/Jobs/HttpRequestJob.cs

@ -1,15 +1,12 @@
using System; using System;
using System.Collections.Generic; using System.Collections.Generic;
using System.Collections.Immutable;
using System.Net.Http; using System.Net.Http;
using System.Net.Http.Headers;
using System.Text;
using System.Threading.Tasks; using System.Threading.Tasks;
using Volo.Abp.Http;
using Volo.Abp.Json;
namespace LINGYUN.Abp.BackgroundTasks.Jobs; namespace LINGYUN.Abp.BackgroundTasks.Jobs;
public class HttpRequestJob : IJobRunnable public class HttpRequestJob : HttpRequestJobBase, IJobRunnable
{ {
public const string PropertyUrl = "url"; public const string PropertyUrl = "url";
public const string PropertyMethod = "method"; public const string PropertyMethod = "method";
@ -20,67 +17,41 @@ public class HttpRequestJob : IJobRunnable
public virtual async Task ExecuteAsync(JobRunnableContext context) public virtual async Task ExecuteAsync(JobRunnableContext context)
{ {
var clientFactory = context.GetRequiredService<IHttpClientFactory>(); InitJob(context);
var client = clientFactory.CreateClient();
var requestMessage = BuildRequestMessage(context);
var response = await client.SendAsync(
requestMessage,
HttpCompletionOption.ResponseHeadersRead);
var stringContent = await response.Content.ReadAsStringAsync();
if (!response.IsSuccessStatusCode && stringContent.IsNullOrWhiteSpace())
{
context.SetResult($"HttpStatusCode: {(int)response.StatusCode}, Reason: {response.ReasonPhrase}");
return;
}
context.SetResult(stringContent);
}
protected virtual HttpRequestMessage BuildRequestMessage(JobRunnableContext context)
{
var url = context.GetString(PropertyUrl); var url = context.GetString(PropertyUrl);
var method = context.GetString(PropertyMethod); var method = context.GetString(PropertyMethod);
context.TryGetString(PropertyData, out var data); context.TryGetJobData(PropertyData, out var data);
context.TryGetString(PropertyContentType, out var contentType); context.TryGetString(PropertyContentType, out var contentType);
var jsonSerializer = context.GetRequiredService<IJsonSerializer>(); var headers = new Dictionary<string, string>();
if (context.TryGetJobData(PropertyHeaders, out var headerInput))
var httpRequestMesasge = new HttpRequestMessage(new HttpMethod(method), url);
if (!data.IsNullOrWhiteSpace())
{ {
// TODO: 需要支持表单类型 if (headerInput is string headerString)
// application/json 支持
httpRequestMesasge.Content = new StringContent(
data,
Encoding.UTF8,
contentType ?? MimeTypes.Application.Json);
}
if (context.TryGetJobData(PropertyHeaders, out var headers))
{
var headersDic = new Dictionary<string, object>();
if (headers is string headerString)
{ {
try try
{ {
headersDic = jsonSerializer.Deserialize<Dictionary<string, object>>(headerString); headers = Deserialize<Dictionary<string, string>>(headerString);
} }
catch { } catch { }
} }
foreach (var header in headersDic)
{
httpRequestMesasge.Headers.Add(header.Key, header.Value.ToString());
}
} }
// TODO: 和 headers 一起?
if (context.TryGetString(PropertyToken, out var accessToken)) var response = await RequestAsync(
context,
new HttpMethod(method),
url,
data,
contentType,
headers.ToImmutableDictionary());
var stringContent = await response.Content.ReadAsStringAsync();
if (!response.IsSuccessStatusCode && stringContent.IsNullOrWhiteSpace())
{ {
httpRequestMesasge.Headers.Authorization = new AuthenticationHeaderValue("Bearer", accessToken); context.SetResult($"HttpStatusCode: {(int)response.StatusCode}, Reason: {response.ReasonPhrase}");
return;
} }
context.SetResult(stringContent);
return httpRequestMesasge;
} }
} }

207
aspnet-core/modules/task-management/LINGYUN.Abp.BackgroundTasks.Jobs/LINGYUN/Abp/BackgroundTasks/Jobs/HttpRequestJobBase.cs

@ -0,0 +1,207 @@
using Microsoft.Extensions.Primitives;
using Newtonsoft.Json;
using System;
using System.Collections.Generic;
using System.Globalization;
using System.Net.Http;
using System.Net.Http.Headers;
using System.Text;
using System.Threading.Tasks;
using Volo.Abp.Content;
using Volo.Abp.Http;
using Volo.Abp.Http.Client;
using Volo.Abp.MultiTenancy;
namespace LINGYUN.Abp.BackgroundTasks.Jobs;
public abstract class HttpRequestJobBase
{
protected ICurrentTenant CurrentTenant { get; set; }
protected virtual void InitJob(JobRunnableContext context)
{
CurrentTenant = context.GetRequiredService<ICurrentTenant>();
}
protected virtual async Task<T> RequestAsync<T>(
JobRunnableContext context,
HttpMethod httpMethod,
string requestUrl,
object data = null,
string contentType = MimeTypes.Application.Json,
IReadOnlyDictionary<string, string> headers = null,
string clientName = null)
{
var response = await RequestAsync(
context,
httpMethod,
requestUrl,
data,
contentType,
headers,
clientName);
var responseContent = response.Content;
if (typeof(T) == typeof(IRemoteStreamContent) ||
typeof(T) == typeof(RemoteStreamContent))
{
return (T)(object)new RemoteStreamContent(
await responseContent.ReadAsStreamAsync(),
responseContent.Headers?.ContentDisposition?.FileNameStar ??
RemoveQuotes(responseContent.Headers?.ContentDisposition?.FileName).ToString(),
responseContent.Headers?.ContentType?.ToString(),
responseContent.Headers?.ContentLength);
}
var stringContent = await responseContent.ReadAsStringAsync();
if (string.IsNullOrWhiteSpace(stringContent))
{
return default;
}
if (typeof(T) == typeof(string))
{
return (T)(object)stringContent;
}
return Deserialize<T>(stringContent);
}
protected virtual async Task<HttpResponseMessage> RequestAsync(
JobRunnableContext context,
HttpMethod httpMethod,
string requestUrl,
object data = null,
string contentType = MimeTypes.Application.Json,
IReadOnlyDictionary<string, string> headers = null,
string clientName = null)
{
var request = BuildRequestMessage(httpMethod, requestUrl, data, contentType, headers);
var clientFactory = context.GetRequiredService<IHttpClientFactory>();
var client = clientName.IsNullOrWhiteSpace()
? clientFactory.CreateClient()
: clientFactory.CreateClient(clientName);
var response = await client.SendAsync(request);
if (!response.IsSuccessStatusCode)
{
await ThrowExceptionForResponseAsync(response);
}
return response;
}
protected virtual HttpRequestMessage BuildRequestMessage(
HttpMethod httpMethod,
string requestUrl,
object data = null,
string contentType = MimeTypes.Application.Json,
IReadOnlyDictionary<string, string> headers = null)
{
var httpRequestMesasge = new HttpRequestMessage(httpMethod, requestUrl);
if (data != null)
{
// TODO: 需要支持表单类型
// application/json 支持
httpRequestMesasge.Content = new StringContent(
Serialize(data),
Encoding.UTF8,
contentType ?? MimeTypes.Application.Json);
}
AddHeaders(httpRequestMesasge, headers);
return httpRequestMesasge;
}
protected virtual void AddHeaders(
HttpRequestMessage requestMessage,
IReadOnlyDictionary<string, string> headers = null)
{
if (CurrentTenant?.Id.HasValue == true)
{
requestMessage.Headers.Add(TenantResolverConsts.DefaultTenantKey, CurrentTenant.Id.ToString());
}
if (headers != null)
{
foreach (var header in headers)
{
requestMessage.Headers.TryAddWithoutValidation(header.Key, header.Value);
}
}
// 不包装请求结果
requestMessage.Headers.TryAddWithoutValidation("_AbpDontWrapResult", "true");
requestMessage.Headers.AcceptLanguage.Add(new StringWithQualityHeaderValue(CultureInfo.CurrentCulture.Name));
}
protected virtual async Task ThrowExceptionForResponseAsync(HttpResponseMessage response)
{
if (response.Headers.Contains(AbpHttpConsts.AbpErrorFormat))
{
RemoteServiceErrorResponse errorResponse;
try
{
errorResponse = Deserialize<RemoteServiceErrorResponse>(
await response.Content.ReadAsStringAsync()
);
}
catch (Exception ex)
{
throw new AbpRemoteCallException(
new RemoteServiceErrorInfo
{
Message = response.ReasonPhrase,
Code = response.StatusCode.ToString()
},
ex
)
{
HttpStatusCode = (int)response.StatusCode
};
}
throw new AbpRemoteCallException(errorResponse.Error)
{
HttpStatusCode = (int)response.StatusCode
};
}
else
{
throw new AbpRemoteCallException(
new RemoteServiceErrorInfo
{
Message = response.ReasonPhrase,
Code = response.StatusCode.ToString()
}
)
{
HttpStatusCode = (int)response.StatusCode
};
}
}
protected virtual T Deserialize<T>(string value)
{
return JsonConvert.DeserializeObject<T>(value);
}
protected virtual string Serialize(object value)
{
return JsonConvert.SerializeObject(value);
}
protected virtual StringSegment RemoveQuotes(StringSegment input)
{
if (!StringSegment.IsNullOrEmpty(input) && input.Length >= 2 && input[0] == '"' && input[input.Length - 1] == '"')
{
input = input.Subsegment(1, input.Length - 2);
}
return input;
}
}

18
aspnet-core/modules/task-management/LINGYUN.Abp.BackgroundTasks.Quartz/LINGYUN/Abp/BackgroundTasks/Quartz/QuartzJobListener.cs

@ -21,16 +21,16 @@ public class QuartzJobListener : JobListenerSupport, ISingletonDependency
protected IClock Clock { get; } protected IClock Clock { get; }
protected IJobEventProvider EventProvider { get; } protected IJobEventProvider EventProvider { get; }
protected IServiceProvider ServiceProvider { get; } protected IServiceScopeFactory ServiceScopeFactory { get; }
public QuartzJobListener( public QuartzJobListener(
IClock clock, IClock clock,
IServiceProvider serviceProvider, IJobEventProvider eventProvider,
IJobEventProvider eventProvider) IServiceScopeFactory serviceScopeFactory)
{ {
Clock = clock; Clock = clock;
ServiceProvider = serviceProvider;
EventProvider = eventProvider; EventProvider = eventProvider;
ServiceScopeFactory = serviceScopeFactory;
Logger = NullLogger<QuartzJobListener>.Instance; Logger = NullLogger<QuartzJobListener>.Instance;
} }
@ -62,7 +62,7 @@ public class QuartzJobListener : JobListenerSupport, ISingletonDependency
return; return;
} }
using var scope = ServiceProvider.CreateScope(); using var scope = ServiceScopeFactory.CreateScope();
var jobEventData = new JobEventData( var jobEventData = new JobEventData(
jobId, jobId,
context.JobDetail.JobType, context.JobDetail.JobType,
@ -108,7 +108,7 @@ public class QuartzJobListener : JobListenerSupport, ISingletonDependency
return; return;
} }
using var scope = ServiceProvider.CreateScope(); using var scope = ServiceScopeFactory.CreateScope();
var jobType = context.JobDetail.JobType; var jobType = context.JobDetail.JobType;
if (jobType.IsGenericType) if (jobType.IsGenericType)
{ {
@ -132,8 +132,10 @@ public class QuartzJobListener : JobListenerSupport, ISingletonDependency
} }
jobEventData.Description = context.JobDetail.Description; jobEventData.Description = context.JobDetail.Description;
jobEventData.RunTime = Clock.Now; jobEventData.RunTime = Clock.Now;
jobEventData.LastRunTime = context.PreviousFireTimeUtc?.LocalDateTime; jobEventData.LastRunTime = context.PreviousFireTimeUtc?.LocalDateTime
jobEventData.NextRunTime = context.NextFireTimeUtc?.LocalDateTime; ?? context.Trigger.GetPreviousFireTimeUtc()?.LocalDateTime;
jobEventData.NextRunTime = context.NextFireTimeUtc?.LocalDateTime
?? context.Trigger.GetNextFireTimeUtc()?.LocalDateTime;
if (context.Result != null) if (context.Result != null)
{ {
jobEventData.Result = context.Result?.ToString(); jobEventData.Result = context.Result?.ToString();

14
aspnet-core/modules/task-management/LINGYUN.Abp.BackgroundTasks.Quartz/LINGYUN/Abp/BackgroundTasks/Quartz/QuartzJobSimpleAdapter.cs

@ -1,6 +1,5 @@
using Microsoft.Extensions.DependencyInjection; using Microsoft.Extensions.DependencyInjection;
using Quartz; using Quartz;
using System;
using System.Collections.Immutable; using System.Collections.Immutable;
using System.Threading.Tasks; using System.Threading.Tasks;
@ -9,23 +8,22 @@ namespace LINGYUN.Abp.BackgroundTasks.Quartz;
public class QuartzJobSimpleAdapter<TJobRunnable> : IJob public class QuartzJobSimpleAdapter<TJobRunnable> : IJob
where TJobRunnable : IJobRunnable where TJobRunnable : IJobRunnable
{ {
protected IServiceProvider ServiceProvider { get; } protected IServiceScopeFactory ServiceScopeFactory { get; }
public QuartzJobSimpleAdapter( public QuartzJobSimpleAdapter(
IServiceProvider serviceProvider) IServiceScopeFactory serviceScopeFactory)
{ {
ServiceProvider = serviceProvider; ServiceScopeFactory = serviceScopeFactory;
} }
public async virtual Task Execute(IJobExecutionContext context) public async virtual Task Execute(IJobExecutionContext context)
{ {
// 任务已经在一个作用域中 using var scope = ServiceScopeFactory.CreateScope();
// using var scope = ServiceProvider.CreateScope(); var jobExecuter = scope.ServiceProvider.GetRequiredService<IJobRunnableExecuter>();
var jobExecuter = ServiceProvider.GetRequiredService<IJobRunnableExecuter>();
var jobContext = new JobRunnableContext( var jobContext = new JobRunnableContext(
typeof(TJobRunnable), typeof(TJobRunnable),
ServiceProvider, scope.ServiceProvider,
context.MergedJobDataMap.ToImmutableDictionary()); context.MergedJobDataMap.ToImmutableDictionary());
await jobExecuter.ExecuteAsync(jobContext); await jobExecuter.ExecuteAsync(jobContext);

2
aspnet-core/modules/task-management/LINGYUN.Abp.BackgroundTasks/LINGYUN/Abp/BackgroundTasks/BackgroundJobAdapter.cs

@ -14,8 +14,8 @@ public class BackgroundJobAdapter<TArgs> : IJobRunnable
public ILogger<BackgroundJobAdapter<TArgs>> Logger { protected get; set; } public ILogger<BackgroundJobAdapter<TArgs>> Logger { protected get; set; }
protected AbpBackgroundJobOptions Options { get; } protected AbpBackgroundJobOptions Options { get; }
protected IServiceScopeFactory ServiceScopeFactory { get; }
protected IBackgroundJobExecuter JobExecuter { get; } protected IBackgroundJobExecuter JobExecuter { get; }
protected IServiceScopeFactory ServiceScopeFactory { get; }
public BackgroundJobAdapter( public BackgroundJobAdapter(
IOptions<AbpBackgroundJobOptions> options, IOptions<AbpBackgroundJobOptions> options,

4
aspnet-core/modules/task-management/LINGYUN.Abp.BackgroundTasks/LINGYUN/Abp/BackgroundTasks/BackgroundWorkerAdapter.cs

@ -14,8 +14,6 @@ public class BackgroundWorkerAdapter<TWorker> : BackgroundWorkerBase, IBackgroun
where TWorker : IBackgroundWorker where TWorker : IBackgroundWorker
{ {
protected IClock Clock => LazyServiceProvider.LazyGetRequiredService<IClock>(); protected IClock Clock => LazyServiceProvider.LazyGetRequiredService<IClock>();
protected IJobStore JobStore => LazyServiceProvider.LazyGetRequiredService<IJobStore>();
protected IJobScheduler JobScheduler => LazyServiceProvider.LazyGetRequiredService<IJobScheduler>();
protected ICurrentTenant CurrentTenant => LazyServiceProvider.LazyGetRequiredService<ICurrentTenant>(); protected ICurrentTenant CurrentTenant => LazyServiceProvider.LazyGetRequiredService<ICurrentTenant>();
private readonly MethodInfo _doWorkAsyncMethod; private readonly MethodInfo _doWorkAsyncMethod;
@ -94,7 +92,7 @@ public class BackgroundWorkerAdapter<TWorker> : BackgroundWorkerBase, IBackgroun
public async Task ExecuteAsync(JobRunnableContext context) public async Task ExecuteAsync(JobRunnableContext context)
{ {
var worker = (IBackgroundWorker)ServiceProvider.GetService(typeof(TWorker)); var worker = (IBackgroundWorker)context.GetService(typeof(TWorker));
var workerContext = new PeriodicBackgroundWorkerContext(ServiceProvider); var workerContext = new PeriodicBackgroundWorkerContext(ServiceProvider);
switch (worker) switch (worker)

10
aspnet-core/modules/task-management/LINGYUN.Abp.BackgroundTasks/LINGYUN/Abp/BackgroundTasks/BackgroundWorkerManager.cs

@ -12,23 +12,21 @@ public class BackgroundWorkerManager : IBackgroundWorkerManager, ISingletonDepen
{ {
protected IJobStore JobStore { get; } protected IJobStore JobStore { get; }
protected IJobScheduler JobScheduler { get; } protected IJobScheduler JobScheduler { get; }
protected IServiceProvider ServiceProvider { get; }
public BackgroundWorkerManager( public BackgroundWorkerManager(
IJobStore jobStore, IJobStore jobStore,
IJobScheduler jobScheduler, IJobScheduler jobScheduler)
IServiceProvider serviceProvider)
{ {
JobStore = jobStore; JobStore = jobStore;
JobScheduler = jobScheduler; JobScheduler = jobScheduler;
ServiceProvider = serviceProvider;
} }
public async Task AddAsync(IBackgroundWorker worker) public async Task AddAsync(IBackgroundWorker worker)
{ {
var adapterType = typeof(BackgroundWorkerAdapter<>).MakeGenericType(ProxyHelper.GetUnProxiedType(worker)); var adapterType = typeof(BackgroundWorkerAdapter<>)
.MakeGenericType(ProxyHelper.GetUnProxiedType(worker));
var workerAdapter = ServiceProvider.GetService(adapterType) as IBackgroundWorkerRunnable; var workerAdapter = Activator.CreateInstance(adapterType) as IBackgroundWorkerRunnable;
var jobInfo = workerAdapter?.BuildWorker(worker); var jobInfo = workerAdapter?.BuildWorker(worker);
if (jobInfo == null) if (jobInfo == null)

2
aspnet-core/modules/task-management/LINGYUN.Abp.BackgroundTasks/LINGYUN/Abp/BackgroundTasks/Internal/JobExecutedEvent.cs

@ -113,7 +113,7 @@ public class JobExecutedEvent : JobEventBase<JobExecutedEvent>, ITransientDepend
{ {
if (exception.InnerException != null) if (exception.InnerException != null)
{ {
return exception.Message + " => " + GetExceptionMessage(exception.InnerException); return GetExceptionMessage(exception.InnerException);
} }
return exception.Message; return exception.Message;

6
aspnet-core/modules/task-management/LINGYUN.Abp.TaskManagement.Application/LINGYUN/Abp/TaskManagement/BackgroundJobInfoAppService.cs

@ -246,11 +246,7 @@ public class BackgroundJobInfoAppService : TaskManagementApplicationService, IBa
backgroundJobInfo.Description = input.Description; backgroundJobInfo.Description = input.Description;
backgroundJobInfo.MaxCount = input.MaxCount; backgroundJobInfo.MaxCount = input.MaxCount;
backgroundJobInfo.MaxTryCount = input.MaxTryCount; backgroundJobInfo.MaxTryCount = input.MaxTryCount;
backgroundJobInfo.Args = input.Args;
foreach (var arg in input.Args)
{
backgroundJobInfo.Args[arg.Key] = arg.Value;
}
backgroundJobInfo.SetPriority(input.Priority); backgroundJobInfo.SetPriority(input.Priority);
switch (input.JobType) switch (input.JobType)

1
aspnet-core/modules/task-management/LINGYUN.Abp.TaskManagement.Domain.Shared/LINGYUN/Abp/TaskManagement/Localization/Resources/en.json

@ -70,6 +70,7 @@
"BackgroundJobs:AddNew": "New Job", "BackgroundJobs:AddNew": "New Job",
"BackgroundJobs:Edit": "Edit Job", "BackgroundJobs:Edit": "Edit Job",
"BackgroundJobs:AddNewArg": "New Args", "BackgroundJobs:AddNewArg": "New Args",
"BackgroundJobs:Paramter": "Job Paramter",
"BackgroundJobs:Pause": "Pause", "BackgroundJobs:Pause": "Pause",
"BackgroundJobs:Resume": "Resume", "BackgroundJobs:Resume": "Resume",
"BackgroundJobs:Trigger": "Trigger", "BackgroundJobs:Trigger": "Trigger",

1
aspnet-core/modules/task-management/LINGYUN.Abp.TaskManagement.Domain.Shared/LINGYUN/Abp/TaskManagement/Localization/Resources/zh-Hans.json

@ -70,6 +70,7 @@
"BackgroundJobs:AddNew": "新建作业", "BackgroundJobs:AddNew": "新建作业",
"BackgroundJobs:Edit": "编辑作业", "BackgroundJobs:Edit": "编辑作业",
"BackgroundJobs:AddNewArg": "添加参数", "BackgroundJobs:AddNewArg": "添加参数",
"BackgroundJobs:Paramter": "作业参数",
"BackgroundJobs:Pause": "暂停", "BackgroundJobs:Pause": "暂停",
"BackgroundJobs:Resume": "恢复", "BackgroundJobs:Resume": "恢复",
"BackgroundJobs:Trigger": "触发", "BackgroundJobs:Trigger": "触发",

2
aspnet-core/modules/task-management/LINGYUN.Abp.TaskManagement.Domain/LINGYUN/Abp/TaskManagement/BackgroundJobInfo.cs

@ -30,7 +30,7 @@ public class BackgroundJobInfo : AuditedAggregateRoot<string>, IMultiTenant
/// <summary> /// <summary>
/// 任务参数 /// 任务参数
/// </summary> /// </summary>
public virtual ExtraPropertyDictionary Args { get; protected set; } public virtual ExtraPropertyDictionary Args { get; set; }
/// <summary> /// <summary>
/// 任务状态 /// 任务状态
/// </summary> /// </summary>

Loading…
Cancel
Save