27
27
import org .springframework .context .annotation .Configuration ;
28
28
import org .springframework .context .annotation .Import ;
29
29
import org .springframework .restdocs .payload .FieldDescriptor ;
30
+ import org .springframework .restdocs .payload .JsonFieldType ;
30
31
import org .springframework .scheduling .Trigger ;
31
32
import org .springframework .scheduling .TriggerContext ;
32
33
import org .springframework .scheduling .annotation .EnableScheduling ;
33
34
import org .springframework .scheduling .annotation .Scheduled ;
34
35
import org .springframework .scheduling .annotation .SchedulingConfigurer ;
36
+ import org .springframework .scheduling .concurrent .SimpleAsyncTaskScheduler ;
35
37
import org .springframework .scheduling .config .ScheduledTaskHolder ;
36
38
37
39
import static org .assertj .core .api .Assertions .assertThat ;
@@ -57,9 +59,12 @@ void scheduledTasks() {
57
59
"com.example.Processor" )),
58
60
responseFields (fieldWithPath ("cron" ).description ("Cron tasks, if any." ),
59
61
targetFieldWithPrefix ("cron.[]." ),
62
+ nextExecutionWithPrefix ("cron.[]." ).description ("Time of the next scheduled execution." ),
60
63
fieldWithPath ("cron.[].expression" ).description ("Cron expression." ),
61
64
fieldWithPath ("fixedDelay" ).description ("Fixed delay tasks, if any." ),
62
65
targetFieldWithPrefix ("fixedDelay.[]." ), initialDelayWithPrefix ("fixedDelay.[]." ),
66
+ nextExecutionWithPrefix ("fixedDelay.[]." )
67
+ .description ("Time of the next scheduled execution." ),
63
68
fieldWithPath ("fixedDelay.[].interval" )
64
69
.description ("Interval, in milliseconds, between the end of the last"
65
70
+ " execution and the start of the next." ),
@@ -68,9 +73,15 @@ void scheduledTasks() {
68
73
fieldWithPath ("fixedRate.[].interval" )
69
74
.description ("Interval, in milliseconds, between the start of each execution." ),
70
75
initialDelayWithPrefix ("fixedRate.[]." ),
76
+ nextExecutionWithPrefix ("fixedRate.[]." )
77
+ .description ("Time of the next scheduled execution." ),
71
78
fieldWithPath ("custom" ).description ("Tasks with custom triggers, if any." ),
72
79
targetFieldWithPrefix ("custom.[]." ),
73
- fieldWithPath ("custom.[].trigger" ).description ("Trigger for the task." ))));
80
+ fieldWithPath ("custom.[].trigger" ).description ("Trigger for the task." ))
81
+ .andWithPrefix ("*.[]." ,
82
+ fieldWithPath ("lastExecution" ).description ("Last execution of this task, if any." )
83
+ .optional ())
84
+ .andWithPrefix ("*.[].lastExecution." , lastExecution ())));
74
85
}
75
86
76
87
private FieldDescriptor targetFieldWithPrefix (String prefix ) {
@@ -81,6 +92,22 @@ private FieldDescriptor initialDelayWithPrefix(String prefix) {
81
92
return fieldWithPath (prefix + "initialDelay" ).description ("Delay, in milliseconds, before first execution." );
82
93
}
83
94
95
+ private FieldDescriptor nextExecutionWithPrefix (String prefix ) {
96
+ return fieldWithPath (prefix + "nextExecution.time" ).description ("Time of the next scheduled execution." );
97
+ }
98
+
99
+ private FieldDescriptor [] lastExecution () {
100
+ return new FieldDescriptor [] {
101
+ fieldWithPath ("status" ).description ("Status of the last execution (STARTED, SUCCESS, ERROR)." ),
102
+ fieldWithPath ("time" ).description ("Time of the last execution." ).type (JsonFieldType .STRING ),
103
+ fieldWithPath ("exception.type" ).description ("Exception type thrown by the task, if any." )
104
+ .type (JsonFieldType .STRING )
105
+ .optional (),
106
+ fieldWithPath ("exception.message" ).description ("Message of the exception thrown by the task, if any." )
107
+ .type (JsonFieldType .STRING )
108
+ .optional () };
109
+ }
110
+
84
111
@ Configuration (proxyBeanMethods = false )
85
112
@ EnableScheduling
86
113
@ Import (BaseDocumentationConfiguration .class )
@@ -96,7 +123,7 @@ void processOrders() {
96
123
97
124
}
98
125
99
- @ Scheduled (fixedDelay = 5000 , initialDelay = 5000 )
126
+ @ Scheduled (fixedDelay = 5000 , initialDelay = 0 )
100
127
void purge () {
101
128
102
129
}
@@ -108,7 +135,10 @@ void retrieveIssues() {
108
135
109
136
@ Bean
110
137
SchedulingConfigurer schedulingConfigurer () {
111
- return (registrar ) -> registrar .addTriggerTask (new CustomTriggeredRunnable (), new CustomTrigger ());
138
+ return (registrar ) -> {
139
+ registrar .setTaskScheduler (new TestTaskScheduler ());
140
+ registrar .addTriggerTask (new CustomTriggeredRunnable (), new CustomTrigger ());
141
+ };
112
142
}
113
143
114
144
static class CustomTrigger implements Trigger {
@@ -124,7 +154,18 @@ static class CustomTriggeredRunnable implements Runnable {
124
154
125
155
@ Override
126
156
public void run () {
157
+ throw new IllegalStateException ("Failed while running custom task" );
158
+ }
159
+
160
+ }
161
+
162
+ static class TestTaskScheduler extends SimpleAsyncTaskScheduler {
127
163
164
+ TestTaskScheduler () {
165
+ setThreadNamePrefix ("test-" );
166
+ // do not log task errors
167
+ setErrorHandler ((throwable ) -> {
168
+ });
128
169
}
129
170
130
171
}
0 commit comments