6
6
7
7
import com .fasterxml .jackson .databind .JsonNode ;
8
8
import com .google .common .annotations .VisibleForTesting ;
9
+ import io .airbyte .commons .lang .Exceptions ;
9
10
import io .airbyte .config .ConnectorJobOutput ;
10
11
import io .airbyte .config .DestinationConnection ;
11
12
import io .airbyte .config .JobCheckConnectionConfig ;
16
17
import io .airbyte .config .StandardCheckConnectionOutput ;
17
18
import io .airbyte .protocol .models .AirbyteCatalog ;
18
19
import io .airbyte .protocol .models .ConnectorSpecification ;
20
+ import io .airbyte .scheduler .persistence .job_error_reporter .ConnectorJobReportingContext ;
21
+ import io .airbyte .scheduler .persistence .job_error_reporter .JobErrorReporter ;
19
22
import io .airbyte .scheduler .persistence .job_factory .OAuthConfigSupplier ;
20
23
import io .airbyte .scheduler .persistence .job_tracker .JobTracker ;
21
24
import io .airbyte .scheduler .persistence .job_tracker .JobTracker .JobState ;
26
29
import java .util .Optional ;
27
30
import java .util .UUID ;
28
31
import java .util .function .Function ;
32
+ import java .util .function .Supplier ;
29
33
import javax .annotation .Nullable ;
34
+ import org .slf4j .Logger ;
35
+ import org .slf4j .LoggerFactory ;
30
36
31
37
public class DefaultSynchronousSchedulerClient implements SynchronousSchedulerClient {
32
38
39
+ private static final Logger LOGGER = LoggerFactory .getLogger (DefaultSynchronousSchedulerClient .class );
40
+
33
41
private final TemporalClient temporalClient ;
34
42
private final JobTracker jobTracker ;
43
+ private final JobErrorReporter jobErrorReporter ;
35
44
private final OAuthConfigSupplier oAuthConfigSupplier ;
36
45
37
46
public DefaultSynchronousSchedulerClient (final TemporalClient temporalClient ,
38
47
final JobTracker jobTracker ,
48
+ final JobErrorReporter jobErrorReporter ,
39
49
final OAuthConfigSupplier oAuthConfigSupplier ) {
40
50
this .temporalClient = temporalClient ;
41
51
this .jobTracker = jobTracker ;
52
+ this .jobErrorReporter = jobErrorReporter ;
42
53
this .oAuthConfigSupplier = oAuthConfigSupplier ;
43
54
}
44
55
@@ -53,10 +64,14 @@ public SynchronousResponse<StandardCheckConnectionOutput> createSourceCheckConne
53
64
.withConnectionConfiguration (sourceConfiguration )
54
65
.withDockerImage (dockerImage );
55
66
67
+ final UUID jobId = UUID .randomUUID ();
68
+ final ConnectorJobReportingContext jobReportingContext = new ConnectorJobReportingContext (jobId , dockerImage );
69
+
56
70
return execute (
57
71
ConfigType .CHECK_CONNECTION_SOURCE ,
72
+ jobReportingContext ,
58
73
source .getSourceDefinitionId (),
59
- jobId -> temporalClient .submitCheckConnection (UUID .randomUUID (), 0 , jobCheckConnectionConfig ),
74
+ () -> temporalClient .submitCheckConnection (UUID .randomUUID (), 0 , jobCheckConnectionConfig ),
60
75
ConnectorJobOutput ::getCheckConnection ,
61
76
source .getWorkspaceId ());
62
77
}
@@ -73,10 +88,14 @@ public SynchronousResponse<StandardCheckConnectionOutput> createDestinationCheck
73
88
.withConnectionConfiguration (destinationConfiguration )
74
89
.withDockerImage (dockerImage );
75
90
91
+ final UUID jobId = UUID .randomUUID ();
92
+ final ConnectorJobReportingContext jobReportingContext = new ConnectorJobReportingContext (jobId , dockerImage );
93
+
76
94
return execute (
77
95
ConfigType .CHECK_CONNECTION_DESTINATION ,
96
+ jobReportingContext ,
78
97
destination .getDestinationDefinitionId (),
79
- jobId -> temporalClient .submitCheckConnection (UUID . randomUUID () , 0 , jobCheckConnectionConfig ),
98
+ () -> temporalClient .submitCheckConnection (jobId , 0 , jobCheckConnectionConfig ),
80
99
ConnectorJobOutput ::getCheckConnection ,
81
100
destination .getWorkspaceId ());
82
101
}
@@ -92,10 +111,14 @@ public SynchronousResponse<AirbyteCatalog> createDiscoverSchemaJob(final SourceC
92
111
.withConnectionConfiguration (sourceConfiguration )
93
112
.withDockerImage (dockerImage );
94
113
114
+ final UUID jobId = UUID .randomUUID ();
115
+ final ConnectorJobReportingContext jobReportingContext = new ConnectorJobReportingContext (jobId , dockerImage );
116
+
95
117
return execute (
96
118
ConfigType .DISCOVER_SCHEMA ,
119
+ jobReportingContext ,
97
120
source .getSourceDefinitionId (),
98
- jobId -> temporalClient .submitDiscoverSchema (UUID . randomUUID () , 0 , jobDiscoverCatalogConfig ),
121
+ () -> temporalClient .submitDiscoverSchema (jobId , 0 , jobDiscoverCatalogConfig ),
99
122
ConnectorJobOutput ::getDiscoverCatalog ,
100
123
source .getWorkspaceId ());
101
124
}
@@ -104,31 +127,39 @@ public SynchronousResponse<AirbyteCatalog> createDiscoverSchemaJob(final SourceC
104
127
public SynchronousResponse <ConnectorSpecification > createGetSpecJob (final String dockerImage ) throws IOException {
105
128
final JobGetSpecConfig jobSpecConfig = new JobGetSpecConfig ().withDockerImage (dockerImage );
106
129
130
+ final UUID jobId = UUID .randomUUID ();
131
+ final ConnectorJobReportingContext jobReportingContext = new ConnectorJobReportingContext (jobId , dockerImage );
132
+
107
133
return execute (
108
134
ConfigType .GET_SPEC ,
135
+ jobReportingContext ,
109
136
null ,
110
- jobId -> temporalClient .submitGetSpec (UUID . randomUUID () , 0 , jobSpecConfig ),
137
+ () -> temporalClient .submitGetSpec (jobId , 0 , jobSpecConfig ),
111
138
ConnectorJobOutput ::getSpec ,
112
139
null );
113
140
}
114
141
115
142
@ VisibleForTesting
116
143
<T , U > SynchronousResponse <T > execute (final ConfigType configType ,
144
+ final ConnectorJobReportingContext jobContext ,
117
145
@ Nullable final UUID connectorDefinitionId ,
118
- final Function < UUID , TemporalResponse <U >> executor ,
146
+ final Supplier < TemporalResponse <U >> executor ,
119
147
final Function <U , T > outputMapper ,
120
148
final UUID workspaceId ) {
121
149
final long createdAt = Instant .now ().toEpochMilli ();
122
- final UUID jobId = UUID . randomUUID ();
150
+ final UUID jobId = jobContext . jobId ();
123
151
try {
124
152
track (jobId , configType , connectorDefinitionId , workspaceId , JobState .STARTED , null );
125
- final TemporalResponse <U > temporalResponse = executor .apply ( jobId );
153
+ final TemporalResponse <U > temporalResponse = executor .get ( );
126
154
final Optional <U > jobOutput = temporalResponse .getOutput ();
127
155
final T mappedOutput = jobOutput .map (outputMapper ).orElse (null );
128
156
final JobState outputState = temporalResponse .getMetadata ().isSucceeded () ? JobState .SUCCEEDED : JobState .FAILED ;
129
157
130
158
track (jobId , configType , connectorDefinitionId , workspaceId , outputState , mappedOutput );
131
- // TODO(pedro): report ConnectorJobOutput's failureReason to the JobErrorReporter, like the above
159
+
160
+ if (outputState == JobState .FAILED && jobOutput .isPresent ()) {
161
+ reportError (configType , jobContext , jobOutput .get (), connectorDefinitionId , workspaceId );
162
+ }
132
163
133
164
final long endedAt = Instant .now ().toEpochMilli ();
134
165
return SynchronousResponse .fromTemporalResponse (
@@ -177,4 +208,34 @@ private <T> void track(final UUID jobId,
177
208
178
209
}
179
210
211
+ private <S , T > void reportError (final ConfigType configType ,
212
+ final ConnectorJobReportingContext jobContext ,
213
+ final T jobOutput ,
214
+ final UUID connectorDefinitionId ,
215
+ final UUID workspaceId ) {
216
+ Exceptions .swallow (() -> {
217
+ switch (configType ) {
218
+ case CHECK_CONNECTION_SOURCE -> jobErrorReporter .reportSourceCheckJobFailure (
219
+ connectorDefinitionId ,
220
+ workspaceId ,
221
+ ((ConnectorJobOutput ) jobOutput ).getFailureReason (),
222
+ jobContext );
223
+ case CHECK_CONNECTION_DESTINATION -> jobErrorReporter .reportDestinationCheckJobFailure (
224
+ connectorDefinitionId ,
225
+ workspaceId ,
226
+ ((ConnectorJobOutput ) jobOutput ).getFailureReason (),
227
+ jobContext );
228
+ case DISCOVER_SCHEMA -> jobErrorReporter .reportDiscoverJobFailure (
229
+ connectorDefinitionId ,
230
+ workspaceId ,
231
+ ((ConnectorJobOutput ) jobOutput ).getFailureReason (),
232
+ jobContext );
233
+ case GET_SPEC -> jobErrorReporter .reportSpecJobFailure (
234
+ ((ConnectorJobOutput ) jobOutput ).getFailureReason (),
235
+ jobContext );
236
+ default -> LOGGER .error ("Tried to report job failure for type {}, but this job type is not supported" , configType );
237
+ }
238
+ });
239
+ }
240
+
180
241
}
0 commit comments