fix(self-operated): remove business collection deadline limits
This commit is contained in:
+3
-4
@@ -304,12 +304,11 @@ public class CollectionQueryService {
|
||||
if(continuous&&!continuousBusiness())return "CONTINUOUS_COLLECTION_DISABLED";
|
||||
if(budget==null||maximum==null||maximum<0||maximum>Integer.MAX_VALUE||reserved==null||reserved>Integer.MAX_VALUE
|
||||
||confirmed==null||confirmed>reserved||started==null
|
||||
||(continuous?budget.hasNonNull("deadlineAtUtc"):deadline==null||!deadline.isAfter(started)))
|
||||
||(budget.hasNonNull("deadlineAtUtc")&&(continuous||deadline==null||!deadline.isAfter(started))))
|
||||
return "BUSINESS_SESSION_BUDGET_MISSING";
|
||||
JsonNode stopped=budget.get("stopReason");
|
||||
if(stopped!=null&&!stopped.isNull())
|
||||
return "BUSINESS_SESSION_STOPPED";
|
||||
if(!continuous&&!clock.instant().isBefore(deadline)&&!Boolean.TRUE.equals(task.businessLocalWorkReady()))return "BUSINESS_SESSION_DEADLINE";
|
||||
return null;
|
||||
}
|
||||
private CollectionResponses.Attempt attemptView(Attempt run,Task task,boolean retryAllowed) {
|
||||
@@ -327,7 +326,7 @@ public class CollectionQueryService {
|
||||
}
|
||||
private String safeMessage(String code,String error) {
|
||||
if("BUSINESS_SESSION_HTTP_LIMIT".equals(code))return "本次正式采集会话的请求预算已耗尽,根任务及关联子任务已停止,不能恢复原任务";
|
||||
if("BUSINESS_SESSION_DEADLINE".equals(code))return "本次正式采集会话已到截止时间,根任务及关联子任务已停止,不能恢复原任务";
|
||||
if("BUSINESS_SESSION_DEADLINE".equals(code))return "该任务曾因旧采集截止时间停止,需核对原检查点和账户保护状态后受控恢复";
|
||||
if(error==null)return null;
|
||||
// Errors are already sanitized by the write side; avoid exposing arbitrary payloads here.
|
||||
return "采集尝试失败,请根据错误码查看受控诊断记录";
|
||||
@@ -354,7 +353,7 @@ public class CollectionQueryService {
|
||||
if(protection.accountPauseReason()!=null&&!protection.accountPauseReason().isBlank())return "ACCOUNT_PAUSED";
|
||||
if(protection.accountCooldownUntil()!=null&&clock.instant().isBefore(protection.accountCooldownUntil()))return "ACCOUNT_COOLDOWN";
|
||||
if(!config.isExclusiveHandoffVerified()||!config.isPriorEgressClosed()||!config.isInflightDrained()||!config.isTransferredBudgetVerified()
|
||||
||(!continuousBusiness()&&(config.getExclusiveGrantExpiresAtUtc()==null||!clock.instant().isBefore(utc(config.getExclusiveGrantExpiresAtUtc())))))return "EXCLUSIVE_GRANT_NOT_VALID";
|
||||
||("VALIDATION".equals(config.getCollectionMode())&&(config.getExclusiveGrantExpiresAtUtc()==null||!clock.instant().isBefore(utc(config.getExclusiveGrantExpiresAtUtc())))))return "EXCLUSIVE_GRANT_NOT_VALID";
|
||||
if("BUSINESS".equals(config.getCollectionMode()))return null;
|
||||
if(config.getDailyRequestBudget()<=0)return "DAILY_BUDGET_NOT_CONFIGURED";
|
||||
if(protection.reservedHttpRequests()!=null&&clock.instant().atZone(BUSINESS_ZONE).toLocalDate().toString().equals(protection.budgetDate())
|
||||
|
||||
+5
-6
@@ -3,21 +3,21 @@ package com.baiyue.lastleg.selfoperated.analytics.request;
|
||||
import com.baiyue.lastleg.selfoperated.analytics.model.SelfopSupport;
|
||||
import java.time.LocalDateTime;
|
||||
|
||||
/** BUSINESS session accounting and time ceiling, shared by the root and descendants. */
|
||||
/** BUSINESS session accounting and explicit stops, shared by the root and descendants. */
|
||||
public final class SelfopBusinessBudget {
|
||||
/** Recorded field only; BUSINESS has no HTTP-count ceiling. New sessions write zero. */
|
||||
public int maxHttp;
|
||||
public int http, confirmedHttp;
|
||||
public boolean continuous;
|
||||
/** Existing deadlines remain recorded evidence, never an execution limit. */
|
||||
public LocalDateTime startedAtUtc, deadlineAtUtc;
|
||||
public String stopReason;
|
||||
|
||||
public static String freeze(LocalDateTime now, int seconds) {
|
||||
if (now == null || seconds < 1)
|
||||
public static String freeze(LocalDateTime now) {
|
||||
if (now == null)
|
||||
throw new IllegalArgumentException("BUSINESS_SESSION_BUDGET_INVALID");
|
||||
var budget = new SelfopBusinessBudget();
|
||||
budget.startedAtUtc = now;
|
||||
budget.deadlineAtUtc = now.plusSeconds(seconds);
|
||||
return SelfopSupport.json(budget);
|
||||
}
|
||||
|
||||
@@ -29,7 +29,7 @@ public final class SelfopBusinessBudget {
|
||||
|
||||
public void validate() {
|
||||
if (http < 0 || confirmedHttp < 0 || confirmedHttp > http
|
||||
|| startedAtUtc == null || (continuous ? deadlineAtUtc != null : deadlineAtUtc == null || !deadlineAtUtc.isAfter(startedAtUtc))
|
||||
|| startedAtUtc == null || deadlineAtUtc != null && (continuous || !deadlineAtUtc.isAfter(startedAtUtc))
|
||||
|| stopReason != null && !stopReason.matches("[A-Z0-9_]{1,64}"))
|
||||
throw new EgressRejectedException("BUSINESS_SESSION_BUDGET_INVALID", false, null);
|
||||
}
|
||||
@@ -37,7 +37,6 @@ public final class SelfopBusinessBudget {
|
||||
public String limit(LocalDateTime now) {
|
||||
validate();
|
||||
if (stopReason != null) return stopReason;
|
||||
if (!continuous && !now.isBefore(deadlineAtUtc)) return "BUSINESS_SESSION_DEADLINE";
|
||||
return null;
|
||||
}
|
||||
}
|
||||
|
||||
+3
-5
@@ -42,9 +42,8 @@ public class SelfopEgressService {
|
||||
if("VALIDATION".equals(context.executionPurpose())&&budget.reservedHttp>=budget.dailyLimit)throw new EgressRejectedException("ACCOUNT_DAILY_BUDGET",false,now.plusHours(8).toLocalDate().plusDays(1).atStartOfDay().minusHours(8));
|
||||
var outbound=new EgressContext(context.sourceAccount(),context.executionPurpose(),String.valueOf(context.rootTaskId()),context.sessionId(),UUID.randomUUID().toString(),context.exclusiveGrantId());
|
||||
var pending=new SelfopApiBudget.Pending();pending.context=outbound;pending.operation=operation;pending.internalRequestHash=requestHash;pending.taskId=context.taskId();pending.runId=context.runId();pending.expiresAtUtc=now.plusSeconds(Math.max(1,Math.min(120,config.getEgressLeaseSeconds())));
|
||||
if(!continuousBusiness(context.executionPurpose())&&pending.expiresAtUtc.isAfter(config.getExclusiveGrantExpiresAtUtc()))pending.expiresAtUtc=config.getExclusiveGrantExpiresAtUtc();
|
||||
if("VALIDATION".equals(context.executionPurpose())&&pending.expiresAtUtc.isAfter(config.getExclusiveGrantExpiresAtUtc()))pending.expiresAtUtc=config.getExclusiveGrantExpiresAtUtc();
|
||||
if(validation!=null&&pending.expiresAtUtc.isAfter(validation.deadlineAtUtc))pending.expiresAtUtc=validation.deadlineAtUtc;
|
||||
if(business!=null&&business.deadlineAtUtc!=null&&pending.expiresAtUtc.isAfter(business.deadlineAtUtc))pending.expiresAtUtc=business.deadlineAtUtc;
|
||||
budget.pending=pending;budget.reservedHttp++;budget.lastRequestAtUtc=now;
|
||||
if(validation!=null){validation.consume(operation,warehouseCode,detailKey);root.setValidationBudgetJson(SelfopSupport.json(validation));mapper.saveRoot(root);}
|
||||
if(business!=null){business.http++;saveBusiness(root,business);}
|
||||
@@ -58,10 +57,9 @@ public class SelfopEgressService {
|
||||
var task=mapper.lockTask(pending.taskId);var run=mapper.lockRun(pending.runId);
|
||||
if(hasBusinessSession(root)){
|
||||
var b=business(root);verifyBusinessTask(task,root);
|
||||
// Authorization preserves the root time/stop fence independently of request accounting.
|
||||
// Explicit root stops remain independent of request accounting and short permit expiry.
|
||||
String limit=b.limit(now);
|
||||
if(limit!=null){stopBusiness(root,b,limit,now);throw reject(limit);}
|
||||
if(b.deadlineAtUtc!=null&&pending.expiresAtUtc.isAfter(b.deadlineAtUtc))pending.expiresAtUtc=b.deadlineAtUtc;
|
||||
}
|
||||
verify(task,run,root,account,now);
|
||||
if(pending.consumed||pending.completed||!now.isBefore(pending.expiresAtUtc))throw reject("EGRESS_PERMIT_REPLAY_OR_EXPIRED");
|
||||
@@ -127,7 +125,7 @@ public class SelfopEgressService {
|
||||
if("OFF".equals(config.getCollectionMode())||!Objects.equals(config.getCollectionMode(),purpose)||!("VALIDATION".equals(purpose)||"BUSINESS".equals(purpose)))throw reject("EGRESS_MODE_REJECTED");
|
||||
if("BUSINESS".equals(purpose)&&!("production".equals(config.getEnvironment())||"test".equals(config.getEnvironment())))throw reject("BUSINESS_ENVIRONMENT_REJECTED");
|
||||
if(!Objects.equals(config.getSourceAccount(),account)||account==null||account.isBlank())throw reject("SOURCE_ACCOUNT_MISMATCH");
|
||||
if(grant==null||grant.isBlank()||!Objects.equals(grant,config.getExclusiveGrantId())||(!continuousBusiness(purpose)&&(config.getExclusiveGrantExpiresAtUtc()==null||!now.isBefore(config.getExclusiveGrantExpiresAtUtc())))||!config.isExclusiveHandoffVerified()||!config.isPriorEgressClosed()||!config.isInflightDrained()||!config.isTransferredBudgetVerified())throw reject("EXCLUSIVE_HANDOFF_UNCONFIRMED");
|
||||
if(grant==null||grant.isBlank()||!Objects.equals(grant,config.getExclusiveGrantId())||("VALIDATION".equals(purpose)&&(config.getExclusiveGrantExpiresAtUtc()==null||!now.isBefore(config.getExclusiveGrantExpiresAtUtc())))||!config.isExclusiveHandoffVerified()||!config.isPriorEgressClosed()||!config.isInflightDrained()||!config.isTransferredBudgetVerified())throw reject("EXCLUSIVE_HANDOFF_UNCONFIRMED");
|
||||
if(("VALIDATION".equals(purpose)&&config.getDailyRequestBudget()<1)||config.getBusinessMinRequestIntervalMs()<1||config.getRequestBudget()<1||config.getTimeBudgetSeconds()<1||config.getMaxRateLimitFailures()<1||config.getCooldownSeconds()<1)throw reject("ACCOUNT_BUDGET_UNCONFIGURED");
|
||||
}
|
||||
private SelfopOutboundDiscoveryScope account(String id){var a=mapper.lockAccount(id);if(a==null)throw reject("EGRESS_ACCOUNT_MISSING");return a;}
|
||||
|
||||
+18
-34
@@ -93,7 +93,7 @@ public class SelfopTaskService {
|
||||
public SelfopSyncTask create(SelfopSyncTask task) {
|
||||
identity(task.getRequestKey(),128); var existing=tasks.selectOne(new QueryWrapper<SelfopSyncTask>()
|
||||
.eq("source_account",task.getSourceAccount()).eq("request_key",task.getRequestKey()));
|
||||
if(existing!=null){require(existing.getRequestHash().equals(task.getRequestHash()),"SELFOP_IDEMPOTENCY_CONFLICT");businessGuard(existing,!localBusinessWork(existing));return existing;}
|
||||
if(existing!=null){require(existing.getRequestHash().equals(task.getRequestHash()),"SELFOP_IDEMPOTENCY_CONFLICT");businessGuard(existing);return existing;}
|
||||
if(task.getExecutionPurpose()==null)task.setExecutionPurpose(configuredPurpose(config));
|
||||
requireExecution(config,task.getExecutionPurpose());
|
||||
var now=utcNow();task.setId(IdWorker.getId());task.setAttemptCount(0);task.setCreatedAt(now);task.setUpdatedAt(now);
|
||||
@@ -121,13 +121,13 @@ public class SelfopTaskService {
|
||||
}else if(task.getRequestKey().startsWith("manual:")&&task.getUpstreamTaskId()==null) {
|
||||
require(controlledBusinessTask(task,tasks::selectById,continuousBusiness(config)),"SELFOP_TEST_MANUAL_TASK_REQUIRED");
|
||||
task.setBusinessRootTaskId(task.getId());
|
||||
task.setBusinessBudgetJson(SelfopBusinessBudget.freeze(now,config.getTimeBudgetSeconds()));
|
||||
task.setBusinessBudgetJson(SelfopBusinessBudget.freeze(now));
|
||||
}else {
|
||||
var parent=businessParent(task);
|
||||
require(parent!=null&&Objects.equals(parent.getSourceAccount(),task.getSourceAccount())&&controlledBusinessTask(parent,tasks::selectById,continuousBusiness(config)),"SELFOP_TEST_MANUAL_TASK_REQUIRED");
|
||||
if("MANUAL_RETRY".equals(task.getTaskType()))require("SUCCEEDED".equals(task.getStatus())&&task.getRequestKey().startsWith("retry:")&&task.getUpstreamTaskId()!=null,"SELFOP_TEST_MANUAL_TASK_REQUIRED");
|
||||
require("MANUAL_RETRY".equals(task.getTaskType())||controlledBusinessTask(task,tasks::selectById,continuousBusiness(config)),"SELFOP_TEST_MANUAL_TASK_REQUIRED");
|
||||
businessGuard(parent,!"WAREHOUSE_SYNC".equals(task.getTaskRole()));task.setBusinessRootTaskId(parent.getBusinessRootTaskId());
|
||||
businessGuard(parent);task.setBusinessRootTaskId(parent.getBusinessRootTaskId());
|
||||
}
|
||||
}
|
||||
task.setStatus(task.getStatus()==null?"READY":task.getStatus());
|
||||
@@ -138,13 +138,13 @@ public class SelfopTaskService {
|
||||
}
|
||||
try{tasks.insert(task);}catch(DuplicateKeyException ignored){existing=tasks.selectOne(new QueryWrapper<SelfopSyncTask>()
|
||||
.eq("source_account",task.getSourceAccount()).eq("request_key",task.getRequestKey()).last("FOR UPDATE"));
|
||||
require(existing!=null&&existing.getRequestHash().equals(task.getRequestHash()),"SELFOP_IDEMPOTENCY_CONFLICT");businessGuard(existing,!localBusinessWork(existing));return existing;}
|
||||
require(existing!=null&&existing.getRequestHash().equals(task.getRequestHash()),"SELFOP_IDEMPOTENCY_CONFLICT");businessGuard(existing);return existing;}
|
||||
return task;
|
||||
}
|
||||
@Transactional(noRollbackFor=BusinessSessionStoppedException.class)
|
||||
public SelfopSyncRun begin(long taskId,SelfopLeaseService.Lease lease) {
|
||||
lockBusinessAccount(taskId);leases.verify(lease);
|
||||
if("test".equals(config.getEnvironment())||continuousBusiness(config)){var preview=tasks.selectById(taskId);businessGuard(preview,!localBusinessWork(preview));}
|
||||
if("test".equals(config.getEnvironment())||continuousBusiness(config)){var preview=tasks.selectById(taskId);businessGuard(preview);}
|
||||
var task=locks.lockTask(taskId);require(task!=null&&!"SUCCEEDED".equals(task.getStatus())&&!"DEAD".equals(task.getStatus()),"SELFOP_TASK_NOT_EXECUTABLE");
|
||||
checkTaskLease(task,lease);
|
||||
requireExecution(config,task.getExecutionPurpose());
|
||||
@@ -186,14 +186,14 @@ public class SelfopTaskService {
|
||||
@Transactional(noRollbackFor=BusinessSessionStoppedException.class)
|
||||
public void yield(long taskId,long runId,SelfopLeaseService.Lease lease) {
|
||||
lockBusinessAccount(taskId);leases.verify(lease);
|
||||
guardBeforeTaskLock(taskId,true);
|
||||
guardBeforeTaskLock(taskId);
|
||||
var now=utcNow();var task=locks.lockTask(taskId);var run=locks.lockRun(runId);checkRunLease(task,run,lease);requireBusiness(task);requireBusiness(run);SelfopProgressProjection.freezeRun(task,run);run.setStatus("YIELDED");run.setFinishedAtUtc(now);run.setUpdatedAt(now);runs.updateById(run);
|
||||
task.setStatus("RETRY_WAIT");task.setNextRetryAtUtc(now.plusSeconds(1));task.setUpdatedAt(now);tasks.updateById(task);
|
||||
}
|
||||
@Transactional(noRollbackFor=BusinessSessionStoppedException.class)
|
||||
public void fail(long taskId,long runId,String code,boolean retryable,SelfopLeaseService.Lease lease) {
|
||||
lockBusinessAccount(taskId);leases.verify(lease);
|
||||
try{guardBeforeTaskLock(taskId,true);}catch(BusinessSessionStoppedException stopped){return;}
|
||||
try{guardBeforeTaskLock(taskId);}catch(BusinessSessionStoppedException stopped){return;}
|
||||
var now=utcNow();var task=locks.lockTask(taskId);var run=locks.lockRun(runId);checkRunLease(task,run,lease);requireBusiness(task);requireBusiness(run);SelfopProgressProjection.freezeRun(task,run);run.setLastPhase(run.getStatus());run.setStatus("FAILED");run.setErrorCode(code);
|
||||
run.setErrorMessage("自营同步失败,需核对运行记录");run.setFinishedAtUtc(now);run.setUpdatedAt(now);runs.updateById(run);
|
||||
// A yielded execution is not a failed request; finite failures are counted separately.
|
||||
@@ -218,14 +218,14 @@ public class SelfopTaskService {
|
||||
lockBusinessAccount(id);
|
||||
var commandQuery=new QueryWrapper<SelfopSyncTask>().eq("source_account",preview.getSourceAccount()).eq("request_key","retry:"+requestKey);
|
||||
var prior=tasks.selectOne(commandQuery);
|
||||
if(prior!=null){require(prior.getRequestHash().equals(hash(List.of(id,requestKey,reason))),"SELFOP_IDEMPOTENCY_CONFLICT");businessGuard(preview,!localBusinessWork(preview));return preview;}
|
||||
if(prior!=null){require(prior.getRequestHash().equals(hash(List.of(id,requestKey,reason))),"SELFOP_IDEMPOTENCY_CONFLICT");businessGuard(preview);return preview;}
|
||||
// Match executor lock ordering: account/warehouse scope first, task second.
|
||||
String activeOwner;LocalDateTime activeUntil;
|
||||
if("ACCOUNT_DISCOVERY".equals(preview.getTaskRole())){var scope=locks.lockDiscovery(preview.getDiscoveryScopeId());require(scope!=null,"SELFOP_SCOPE_MISSING");activeOwner=scope.getLeaseOwner();activeUntil=scope.getLeaseUntilUtc();}
|
||||
else{var scope=locks.lockScope(preview.getScopeId());require(scope!=null,"SELFOP_SCOPE_MISSING");activeOwner=scope.getLeaseOwner();activeUntil=scope.getLeaseUntilUtc();}
|
||||
prior=tasks.selectOne(new QueryWrapper<SelfopSyncTask>().eq("source_account",preview.getSourceAccount()).eq("request_key","retry:"+requestKey).last("FOR UPDATE"));
|
||||
if(prior!=null){require(prior.getRequestHash().equals(hash(List.of(id,requestKey,reason))),"SELFOP_IDEMPOTENCY_CONFLICT");return tasks.selectById(id);}
|
||||
businessGuard(preview,!localBusinessWork(preview));
|
||||
businessGuard(preview);
|
||||
require(SelfopLeaseService.available(activeOwner,activeUntil,utcNow()),"SELFOP_RETRY_LEASE_BUSY");
|
||||
var original=locks.lockTask(id);require(original!=null,"SELFOP_TASK_MISSING");
|
||||
requireBusiness(original);requireExecution(config,original.getExecutionPurpose());
|
||||
@@ -245,7 +245,7 @@ public class SelfopTaskService {
|
||||
public List<SelfopSyncTask> due(int limit){return continuousBusiness(config)?locks.dueContinuous(utcNow(),limit,config.getSourceAccount()):locks.due(utcNow(),limit,config.getCollectionMode());}
|
||||
@Transactional(noRollbackFor=BusinessSessionStoppedException.class)
|
||||
public void candidateFinished(long taskId,long runId,SelfopLeaseService.Lease lease) {
|
||||
lockBusinessAccount(taskId);leases.verify(lease);guardBeforeTaskLock(taskId,false);var task=locks.lockTask(taskId);var run=locks.lockRun(runId);
|
||||
lockBusinessAccount(taskId);leases.verify(lease);guardBeforeTaskLock(taskId);var task=locks.lockTask(taskId);var run=locks.lockRun(runId);
|
||||
checkRunLease(task,run,lease);
|
||||
require("READY".equals(run.getStatus()),"SELFOP_CANDIDATE_NOT_READY");
|
||||
run.setFinishedAtUtc(utcNow());run.setUpdatedAt(utcNow());runs.updateById(run);
|
||||
@@ -254,7 +254,7 @@ public class SelfopTaskService {
|
||||
}
|
||||
@Transactional(noRollbackFor=BusinessSessionStoppedException.class)
|
||||
public void waitForBudget(long taskId,long runId,LocalDateTime until,SelfopLeaseService.Lease lease) {
|
||||
lockBusinessAccount(taskId);leases.verify(lease);if("test".equals(config.getEnvironment())||continuousBusiness(config)){var preview=tasks.selectById(taskId);businessGuard(preview,!localBusinessWork(preview));}var task=locks.lockTask(taskId);var run=locks.lockRun(runId);checkRunLease(task,run,lease);requireBusiness(task);requireBusiness(run);
|
||||
lockBusinessAccount(taskId);leases.verify(lease);if("test".equals(config.getEnvironment())||continuousBusiness(config)){var preview=tasks.selectById(taskId);businessGuard(preview);}var task=locks.lockTask(taskId);var run=locks.lockRun(runId);checkRunLease(task,run,lease);requireBusiness(task);requireBusiness(run);
|
||||
SelfopProgressProjection.freezeRun(task,run);run.setLastPhase(run.getStatus());run.setStatus("YIELDED");run.setFinishedAtUtc(utcNow());run.setUpdatedAt(utcNow());runs.updateById(run);
|
||||
task.setStatus("RETRY_WAIT");task.setNextRetryAtUtc(until);task.setUpdatedAt(utcNow());tasks.updateById(task);
|
||||
}
|
||||
@@ -264,17 +264,17 @@ public class SelfopTaskService {
|
||||
public CollectionCheckpoint checkpoint(SelfopSyncTask observedTask,SelfopSyncRun observedRun,SelfopLeaseService.Lease lease) {
|
||||
long taskId=observedTask.getId();lockBusinessAccount(taskId);leases.verify(lease);
|
||||
if("test".equals(config.getEnvironment())||continuousBusiness(config)) {
|
||||
var preview=tasks.selectById(taskId);require(preview!=null,"SELFOP_TASK_MISSING");businessGuard(preview,false,false);
|
||||
var preview=tasks.selectById(taskId);require(preview!=null,"SELFOP_TASK_MISSING");businessGuard(preview,false);
|
||||
}
|
||||
var task=locks.lockTask(taskId);var run=locks.lockRun(observedRun.getId());checkRunLease(task,run,lease);
|
||||
requireBusiness(task);requireBusiness(run);
|
||||
require("RUNNING".equals(task.getStatus())&&"FETCHING".equals(run.getStatus()),"SELFOP_COLLECTION_TERMINATED");
|
||||
return new CollectionCheckpoint(task,run);
|
||||
}
|
||||
/** Only TEST manual collection has a session ceiling; production retains its resumable scheduler. */
|
||||
/** Explicit session stops remain binding after removal of artificial BUSINESS deadlines. */
|
||||
public static final class BusinessSessionStoppedException extends com.baiyue.common.core.exception.BizException {
|
||||
private final String reason;
|
||||
BusinessSessionStoppedException(String reason){super("本次测试采集会话已结束或预算无效,请核对记录后新建有界任务");this.reason=reason;}
|
||||
BusinessSessionStoppedException(String reason){super("本次采集会话已停止或计数无效,请核对停止原因与原检查点");this.reason=reason;}
|
||||
public String reason(){return reason;}
|
||||
}
|
||||
private boolean testBusiness(SelfopSyncTask task){return task!=null&&("test".equals(config.getEnvironment())||continuousBusiness(config))&&"BUSINESS".equals(task.getExecutionPurpose());}
|
||||
@@ -290,27 +290,12 @@ public class SelfopTaskService {
|
||||
var account=accounts.selectOne(new QueryWrapper<SelfopOutboundDiscoveryScope>().eq("source_account",task.getSourceAccount()));
|
||||
require(account!=null,"SELFOP_SCOPE_MISSING");locks.lockDiscovery(account.getId());
|
||||
}
|
||||
private void guardBeforeTaskLock(long id,boolean checkDeadline){
|
||||
private void guardBeforeTaskLock(long id){
|
||||
if(!"test".equals(config.getEnvironment())&&!continuousBusiness(config))return;
|
||||
var task=tasks.selectById(id);businessGuard(task,checkDeadline);
|
||||
var task=tasks.selectById(id);businessGuard(task);
|
||||
}
|
||||
private boolean localBusinessWork(SelfopSyncTask task){
|
||||
if(!testBusiness(task)||!"WAREHOUSE_SYNC".equals(task.getTaskRole()))return false;
|
||||
var scope=scopes.selectById(task.getScopeId());
|
||||
if(scope==null||!"OUTBOUND".equals(scope.getDataFamily()))return false;
|
||||
if("REBUILD".equals(task.getTaskType())||"APPLIED".equals(task.getApplyState()))return true;
|
||||
if(task.getRoutingManifestJson()==null)return false;
|
||||
Map<?,?> manifest;
|
||||
try{manifest=read(task.getRoutingManifestJson(),Map.class);}catch(IllegalArgumentException invalid){return false;}
|
||||
if(manifest==null||!Boolean.TRUE.equals(manifest.get("directoryComplete"))||!(manifest.get("objects") instanceof Map<?,?> objects))return false;
|
||||
return objects.values().stream().allMatch(value->{
|
||||
if(!(value instanceof Map<?,?> entry))return false;
|
||||
Object id=entry.get("effectiveStageId");
|
||||
return (id instanceof Long||id instanceof Integer)&&((Number)id).longValue()>0;
|
||||
});
|
||||
}
|
||||
private void businessGuard(SelfopSyncTask task,boolean checkDeadline){businessGuard(task,checkDeadline,true);}
|
||||
private void businessGuard(SelfopSyncTask task,boolean checkDeadline,boolean terminate){
|
||||
private void businessGuard(SelfopSyncTask task){businessGuard(task,true);}
|
||||
private void businessGuard(SelfopSyncTask task,boolean terminate){
|
||||
if(!testBusiness(task))return;
|
||||
require(controlledBusinessTask(task,tasks::selectById,continuousBusiness(config)),"SELFOP_TEST_MANUAL_TASK_REQUIRED");
|
||||
require(task.getBusinessRootTaskId()!=null,"BUSINESS_SESSION_ROOT_REQUIRED");
|
||||
@@ -327,7 +312,6 @@ public class SelfopTaskService {
|
||||
var budget=read(root.getBusinessBudgetJson(),SelfopBusinessBudget.class);budget.validate();
|
||||
require(!budget.continuous||(continuousBusiness(config)&&continuousBusinessRoot(root)),"SELFOP_CONTINUOUS_COLLECTION_DISABLED");
|
||||
String reason=budget.stopReason;
|
||||
if(reason==null&&checkDeadline&&!budget.continuous&&!utcNow().isBefore(budget.deadlineAtUtc))reason="BUSINESS_SESSION_DEADLINE";
|
||||
if(reason==null&&"DEAD".equals(root.getStatus()))reason="BUSINESS_SESSION_STOPPED";
|
||||
if(reason==null)return;
|
||||
if(!terminate)throw new BusinessSessionStoppedException(reason);
|
||||
|
||||
Reference in New Issue
Block a user