Skip to content
Projects
Groups
Snippets
Help
Loading...
Help
Contribute to GitLab
Sign in
Toggle navigation
Z
zhmes-agecal
Project
Project
Details
Activity
Cycle Analytics
Repository
Repository
Files
Commits
Branches
Tags
Contributors
Graph
Compare
Charts
Issues
0
Issues
0
List
Board
Labels
Milestones
Merge Requests
0
Merge Requests
0
CI / CD
CI / CD
Pipelines
Jobs
Schedules
Charts
Wiki
Wiki
Snippets
Snippets
Members
Members
Collapse sidebar
Close sidebar
Activity
Graph
Charts
Create a new issue
Jobs
Commits
Issue Boards
Open sidebar
耿迪迪
zhmes-agecal
Commits
f13c55b9
Commit
f13c55b9
authored
Sep 24, 2025
by
wanghao
Browse files
Options
Browse Files
Download
Email Patches
Plain Diff
1 指令指令完成,但是 没有检测到机械臂完成。
parent
d34ebdc1
Show whitespace changes
Inline
Side-by-side
Showing
4 changed files
with
166 additions
and
32 deletions
+166
-32
application-test.yml
zhmes-agecal-admin/src/main/resources/application-test.yml
+2
-1
DeviceCommunicationJob.java
...n/java/com/zehong/system/task/DeviceCommunicationJob.java
+68
-15
DeviceTaskScheduler.java
...main/java/com/zehong/system/task/DeviceTaskScheduler.java
+53
-16
QuartzJobListener.java
...c/main/java/com/zehong/system/task/QuartzJobListener.java
+43
-0
No files found.
zhmes-agecal-admin/src/main/resources/application-test.yml
View file @
f13c55b9
...
@@ -81,7 +81,8 @@ spring:
...
@@ -81,7 +81,8 @@ spring:
# 是否使用属性文件存储JobDataMaps
# 是否使用属性文件存储JobDataMaps
useProperties
:
true
useProperties
:
true
# 错过触发阈值(毫秒)
# 错过触发阈值(毫秒)
misfireThreshold
:
60000
misfireThreshold
:
300000
tolerateJobFailure
:
true
# 是否启用集群功能
# 是否启用集群功能
isClustered
:
false
isClustered
:
false
# 集群检查间隔(毫秒)
# 集群检查间隔(毫秒)
...
...
zhmes-agecal-system/src/main/java/com/zehong/system/task/DeviceCommunicationJob.java
View file @
f13c55b9
...
@@ -58,24 +58,77 @@ public class DeviceCommunicationJob implements Job {
...
@@ -58,24 +58,77 @@ public class DeviceCommunicationJob implements Job {
@Override
@Override
public
void
execute
(
JobExecutionContext
context
)
{
public
void
execute
(
JobExecutionContext
context
)
{
// 绝对确保任何异常都不会传播到Quartz
try
{
log
.
info
(
"=== DeviceCommunicationJob 开始执行 ==="
);
log
.
info
(
"=== DeviceCommunicationJob 开始执行 ==="
);
executeWithFullProtection
(
context
);
log
.
info
(
"=== DeviceCommunicationJob 执行完成 ==="
);
}
catch
(
Throwable
e
)
{
// 捕获Throwable而不是Exception
// 关键:记录错误但不传播到Quartz
log
.
error
(
"=== 任务执行异常(已完全捕获,不影响触发器) ==="
,
e
);
safeRecordAlarm
(
context
,
"任务异常已捕获: "
+
e
.
getClass
().
getSimpleName
());
}
}
private
void
safeRecordAlarm
(
JobExecutionContext
context
,
String
message
)
{
try
{
JobDataMap
data
=
context
.
getJobDetail
().
getJobDataMap
();
String
fStoreyIdStr
=
data
!=
null
?
data
.
getString
(
"fStoreyId"
)
:
"unknown"
;
TEquipmentAlarmData
alarm
=
new
TEquipmentAlarmData
();
alarm
.
setfAlarmType
(
"03"
);
alarm
.
setfEquipmentCode
(
fStoreyIdStr
);
alarm
.
setfAlarmData
(
message
);
alarm
.
setfCreateTime
(
new
Date
());
alarmDataService
.
insertTEquipmentAlarmData
(
alarm
);
}
catch
(
Exception
e
)
{
log
.
error
(
"记录告警失败"
,
e
);
}
}
private
void
executeWithFullProtection
(
JobExecutionContext
context
)
{
// 移除所有CompletableFuture和多线程,简化执行流程
String
fStoreyIdStr
=
null
;
try
{
JobDataMap
data
=
context
.
getJobDetail
().
getJobDataMap
();
fStoreyIdStr
=
data
.
getString
(
"fStoreyId"
);
if
(
StringUtils
.
isBlank
(
fStoreyIdStr
))
{
log
.
warn
(
"fStoreyId为空,跳过执行"
);
return
;
}
Long
fStoreyId
=
Long
.
parseLong
(
fStoreyIdStr
);
TStoreyInfo
tStoreyInfo
=
tStoreyInfoMapper
.
selectTStoreyInfoById
(
fStoreyId
);
if
(
tStoreyInfo
==
null
||
StringUtils
.
isBlank
(
tStoreyInfo
.
getfIp
()))
{
log
.
warn
(
"设备信息无效,跳过执行"
);
return
;
}
// 简化执行:只执行最基本的通信测试
executeSimpleCommunicationTest
(
tStoreyInfo
,
fStoreyId
);
}
catch
(
NumberFormatException
e
)
{
log
.
warn
(
"参数格式错误: {}"
,
fStoreyIdStr
,
e
);
}
catch
(
Exception
e
)
{
log
.
error
(
"通信任务执行异常"
,
e
);
// 不抛出!只记录日志
}
}
private
void
executeSimpleCommunicationTest
(
TStoreyInfo
tStoreyInfo
,
Long
fStoreyId
)
{
String
ip
=
tStoreyInfo
.
getfIp
();
// 只测试第一个设备,简化逻辑
try
{
try
{
// 使用单线程顺序执行,避免并发问题
ModbusMaster
master
=
createModbusMaster
(
ip
,
501
);
CompletableFuture
<
Void
>
future
=
CompletableFuture
.
runAsync
(()
->
{
int
[]
result
=
readDeviceRegistersOnce
(
master
,
1
);
// 只读第一个设备
executeJobSafely
(
context
);
master
.
destroy
();
},
sequentialExecutor
);
log
.
info
(
"设备通信测试成功: fStoreyId={}, 状态值={}"
,
fStoreyId
,
// 设置总超时
result
.
length
>
1
?
result
[
1
]
:
"无数据"
);
future
.
get
(
180
,
TimeUnit
.
SECONDS
);
// 3分钟总超时
log
.
info
(
"=== DeviceCommunicationJob 正常完成 ==="
);
}
catch
(
TimeoutException
e
)
{
log
.
error
(
"任务执行超时"
,
e
);
recordAlarm
(
context
,
"任务执行超时(3分钟)"
);
}
catch
(
Exception
e
)
{
}
catch
(
Exception
e
)
{
log
.
error
(
"任务执行异常(已捕获,不会影响触发器)"
,
e
);
log
.
warn
(
"设备通信测试失败: fStoreyId={}, IP={}"
,
fStoreyId
,
ip
,
e
);
recordAlarm
(
context
,
"任务执行异常: "
+
e
.
getMessage
());
// 不抛出异常!
}
}
}
}
private
void
executeJobSafely
(
JobExecutionContext
context
)
{
private
void
executeJobSafely
(
JobExecutionContext
context
)
{
...
...
zhmes-agecal-system/src/main/java/com/zehong/system/task/DeviceTaskScheduler.java
View file @
f13c55b9
...
@@ -6,6 +6,7 @@ import org.slf4j.Logger;
...
@@ -6,6 +6,7 @@ import org.slf4j.Logger;
import
org.slf4j.LoggerFactory
;
import
org.slf4j.LoggerFactory
;
import
org.springframework.stereotype.Service
;
import
org.springframework.stereotype.Service
;
import
javax.annotation.PostConstruct
;
import
javax.annotation.Resource
;
import
javax.annotation.Resource
;
import
java.time.Instant
;
import
java.time.Instant
;
import
java.time.temporal.ChronoUnit
;
import
java.time.temporal.ChronoUnit
;
...
@@ -35,6 +36,12 @@ public class DeviceTaskScheduler {
...
@@ -35,6 +36,12 @@ public class DeviceTaskScheduler {
// 常量:Cron周期(3分钟)、任务有效期(7天)
// 常量:Cron周期(3分钟)、任务有效期(7天)
private
static
final
String
CRON_EXPRESSION
=
"0 0/5 * * * ?"
;
private
static
final
String
CRON_EXPRESSION
=
"0 0/5 * * * ?"
;
private
static
final
int
TASK_VALID_DAYS
=
7
;
private
static
final
int
TASK_VALID_DAYS
=
7
;
@PostConstruct
public
void
init
()
throws
SchedulerException
{
scheduler
.
getListenerManager
().
addJobListener
(
new
QuartzJobListener
());
}
/**
/**
* 创建设备监控任务(入口:增加调度器健康检查、任务去重)
* 创建设备监控任务(入口:增加调度器健康检查、任务去重)
*/
*/
...
@@ -81,6 +88,15 @@ public class DeviceTaskScheduler {
...
@@ -81,6 +88,15 @@ public class DeviceTaskScheduler {
private
void
createHourlyCommunicationJob
(
Long
fStoreyId
)
throws
SchedulerException
{
private
void
createHourlyCommunicationJob
(
Long
fStoreyId
)
throws
SchedulerException
{
String
jobId
=
"COMM_"
+
fStoreyId
;
String
jobId
=
"COMM_"
+
fStoreyId
;
JobKey
jobKey
=
new
JobKey
(
jobId
,
JOB_GROUP
);
JobKey
jobKey
=
new
JobKey
(
jobId
,
JOB_GROUP
);
TriggerKey
triggerKey
=
new
TriggerKey
(
jobId
+
"_TRIGGER"
,
TRIGGER_GROUP
);
// 先删除旧的触发器和任务(彻底清理)
if
(
scheduler
.
checkExists
(
triggerKey
))
{
scheduler
.
unscheduleJob
(
triggerKey
);
}
if
(
scheduler
.
checkExists
(
jobKey
))
{
scheduler
.
deleteJob
(
jobKey
);
}
JobDetail
job
=
JobBuilder
.
newJob
(
DeviceCommunicationJob
.
class
)
JobDetail
job
=
JobBuilder
.
newJob
(
DeviceCommunicationJob
.
class
)
.
withIdentity
(
jobKey
)
.
withIdentity
(
jobKey
)
...
@@ -88,26 +104,17 @@ public class DeviceTaskScheduler {
...
@@ -88,26 +104,17 @@ public class DeviceTaskScheduler {
.
storeDurably
(
false
)
.
storeDurably
(
false
)
.
build
();
.
build
();
//
使用更宽松的misfire策略
//
关键修复:使用StartAt而不是StartNow
CronTrigger
trigger
=
TriggerBuilder
.
newTrigger
()
CronTrigger
trigger
=
TriggerBuilder
.
newTrigger
()
.
withIdentity
(
jobId
+
"_TRIGGER"
,
TRIGGER_GROUP
)
.
withIdentity
(
triggerKey
)
.
forJob
(
jobKey
)
.
forJob
(
jobKey
)
.
withSchedule
(
CronScheduleBuilder
.
cronSchedule
(
CRON_EXPRESSION
)
.
withSchedule
(
CronScheduleBuilder
.
cronSchedule
(
"0 0/3 * * * ?"
)
// 改为3分钟
.
withMisfireHandlingInstructionDoNothing
())
// 错过就忽略
.
withMisfireHandlingInstructionDoNothing
())
.
start
Now
()
.
start
At
(
new
Date
())
// 显式设置开始时间:cite[1]
.
build
();
.
build
();
// 清理旧任务时更温和
Date
nextFireTime
=
scheduler
.
scheduleJob
(
job
,
trigger
);
if
(
scheduler
.
checkExists
(
jobKey
))
{
log
.
info
(
"通信任务[{}]创建成功,下次执行:{}"
,
jobId
,
nextFireTime
);
scheduler
.
deleteJob
(
jobKey
);
try
{
Thread
.
sleep
(
100
);
// 短暂等待确保清理完成
}
catch
(
InterruptedException
e
)
{
throw
new
RuntimeException
(
e
);
}
}
scheduler
.
scheduleJob
(
job
,
trigger
);
}
}
/**
/**
...
@@ -251,5 +258,35 @@ public class DeviceTaskScheduler {
...
@@ -251,5 +258,35 @@ public class DeviceTaskScheduler {
finalTrigger
!=
null
?
finalTrigger
.
getNextFireTime
()
:
"不存在"
,
finalTrigger
!=
null
?
finalTrigger
.
getNextFireTime
()
:
"不存在"
,
finalTrigger
!=
null
?
finalTrigger
.
getEndTime
()
:
"不存在"
);
finalTrigger
!=
null
?
finalTrigger
.
getEndTime
()
:
"不存在"
);
}
}
/**
* 监控并修复ERROR状态的触发器
*/
public
void
monitorAndRepairTriggers
()
throws
SchedulerException
{
for
(
String
groupName
:
scheduler
.
getTriggerGroupNames
())
{
for
(
TriggerKey
triggerKey
:
scheduler
.
getTriggerKeys
(
GroupMatcher
.
triggerGroupEquals
(
groupName
)))
{
Trigger
.
TriggerState
state
=
scheduler
.
getTriggerState
(
triggerKey
);
if
(
state
==
Trigger
.
TriggerState
.
ERROR
)
{
log
.
warn
(
"发现ERROR状态触发器: {}"
,
triggerKey
);
repairErrorTrigger
(
triggerKey
);
}
}
}
}
private
void
repairErrorTrigger
(
TriggerKey
triggerKey
)
throws
SchedulerException
{
Trigger
oldTrigger
=
scheduler
.
getTrigger
(
triggerKey
);
JobKey
jobKey
=
oldTrigger
.
getJobKey
();
// 重新创建触发器
Trigger
newTrigger
=
TriggerBuilder
.
newTrigger
()
.
withIdentity
(
triggerKey
)
.
forJob
(
jobKey
)
.
withSchedule
(
CronScheduleBuilder
.
cronSchedule
(
"0 0/3 * * * ?"
)
.
withMisfireHandlingInstructionDoNothing
())
.
startAt
(
new
Date
())
// 关键:使用当前时间
.
build
();
scheduler
.
rescheduleJob
(
triggerKey
,
newTrigger
);
log
.
info
(
"触发器修复完成: {}"
,
triggerKey
);
}
}
}
zhmes-agecal-system/src/main/java/com/zehong/system/task/QuartzJobListener.java
0 → 100644
View file @
f13c55b9
package
com
.
zehong
.
system
.
task
;
import
org.quartz.JobExecutionContext
;
import
org.quartz.JobExecutionException
;
import
org.quartz.JobListener
;
import
org.quartz.SchedulerException
;
import
org.slf4j.Logger
;
import
org.slf4j.LoggerFactory
;
import
org.springframework.stereotype.Component
;
/**
* @author lenovo
* @date 2025/9/24
* @description TODO
*/
@Component
public
class
QuartzJobListener
implements
JobListener
{
private
static
final
Logger
log
=
LoggerFactory
.
getLogger
(
QuartzJobListener
.
class
);
@Override
public
String
getName
()
{
return
"DeviceCommunicationJobListener"
;
}
@Override
public
void
jobToBeExecuted
(
JobExecutionContext
context
)
{
log
.
info
(
"Job即将执行: {}"
,
context
.
getJobDetail
().
getKey
());
}
@Override
public
void
jobExecutionVetoed
(
JobExecutionContext
context
)
{
log
.
warn
(
"Job执行被否决: {}"
,
context
.
getJobDetail
().
getKey
());
}
@Override
public
void
jobWasExecuted
(
JobExecutionContext
context
,
JobExecutionException
jobException
)
{
if
(
jobException
!=
null
)
{
log
.
error
(
"Job执行异常: {}"
,
context
.
getJobDetail
().
getKey
(),
jobException
);
}
else
{
log
.
info
(
"Job执行完成: {}"
,
context
.
getJobDetail
().
getKey
());
}
}
}
\ No newline at end of file
Write
Preview
Markdown
is supported
0%
Try again
or
attach a new file
Attach a file
Cancel
You are about to add
0
people
to the discussion. Proceed with caution.
Finish editing this message first!
Cancel
Please
register
or
sign in
to comment