5
5
6
6
package org.opensearch.alerting.transport
7
7
8
- import kotlinx.coroutines.CoroutineName
8
+ import kotlinx.coroutines.CoroutineScope
9
9
import kotlinx.coroutines.Dispatchers
10
- import kotlinx.coroutines.GlobalScope
11
10
import kotlinx.coroutines.launch
12
11
import org.apache.logging.log4j.LogManager
13
12
import org.opensearch.OpenSearchStatusException
@@ -25,6 +24,7 @@ import org.opensearch.action.search.SearchResponse
25
24
import org.opensearch.action.support.ActionFilters
26
25
import org.opensearch.action.support.HandledTransportAction
27
26
import org.opensearch.action.support.IndicesOptions
27
+ import org.opensearch.action.support.WriteRequest
28
28
import org.opensearch.action.support.master.AcknowledgedResponse
29
29
import org.opensearch.alerting.MonitorMetadataService
30
30
import org.opensearch.alerting.opensearchapi.suspendUntil
@@ -57,6 +57,7 @@ import kotlin.coroutines.resume
57
57
import kotlin.coroutines.resumeWithException
58
58
import kotlin.coroutines.suspendCoroutine
59
59
60
+ private val scope: CoroutineScope = CoroutineScope (Dispatchers .IO )
60
61
private val log = LogManager .getLogger(TransportDeleteMonitorAction ::class .java)
61
62
62
63
class TransportDeleteMonitorAction @Inject constructor(
@@ -87,8 +88,7 @@ class TransportDeleteMonitorAction @Inject constructor(
87
88
if (! validateUserBackendRoles(user, actionListener)) {
88
89
return
89
90
}
90
-
91
- GlobalScope .launch(Dispatchers .IO + CoroutineName (" DeleteMonitorAction" )) {
91
+ scope.launch {
92
92
DeleteMonitorHandler (client, actionListener, deleteRequest, user, transformedRequest.monitorId).resolveUserAndStart()
93
93
}
94
94
}
@@ -109,16 +109,15 @@ class TransportDeleteMonitorAction @Inject constructor(
109
109
checkUserPermissionsWithResource(user, monitor.user, actionListener, " monitor" , monitorId)
110
110
111
111
if (canDelete) {
112
- val deleteResponse = deleteMonitor(monitor)
113
- deleteDocLevelMonitorQueriesAndIndices(monitor)
114
- deleteMetadata(monitor)
112
+ val deleteResponse = deleteAllResourcesForMonitor(client, monitor, deleteRequest, monitorId)
115
113
actionListener.onResponse(DeleteMonitorResponse (deleteResponse.id, deleteResponse.version))
116
114
} else {
117
115
actionListener.onFailure(
118
116
AlertingException (" Not allowed to delete this monitor!" , RestStatus .FORBIDDEN , IllegalStateException ())
119
117
)
120
118
}
121
119
} catch (t: Exception ) {
120
+ log.error(" Failed to delete monitor ${deleteRequest.id()} " , t)
122
121
actionListener.onFailure(AlertingException .wrap(t))
123
122
}
124
123
}
@@ -140,68 +139,102 @@ class TransportDeleteMonitorAction @Inject constructor(
140
139
)
141
140
return ScheduledJob .parse(xcp, getResponse.id, getResponse.version) as Monitor
142
141
}
142
+ }
143
+
144
+ companion object {
145
+ @JvmStatic
146
+ suspend fun deleteAllResourcesForMonitor (
147
+ client : Client ,
148
+ monitor : Monitor ,
149
+ deleteRequest : DeleteRequest ,
150
+ monitorId : String ,
151
+ ): DeleteResponse {
152
+ val deleteResponse = deleteMonitorDocument(client, deleteRequest)
153
+ deleteMetadata(client, monitor)
154
+ deleteDocLevelMonitorQueriesAndIndices(client, monitor, monitorId)
155
+ return deleteResponse
156
+ }
143
157
144
- private suspend fun deleteMonitor ( monitor : Monitor ): DeleteResponse {
158
+ private suspend fun deleteMonitorDocument ( client : Client , deleteRequest : DeleteRequest ): DeleteResponse {
145
159
return client.suspendUntil { delete(deleteRequest, it) }
146
160
}
147
161
148
- private suspend fun deleteMetadata (monitor : Monitor ) {
162
+ suspend fun deleteMetadata (client : Client , monitor : Monitor ) {
149
163
val deleteRequest = DeleteRequest (ScheduledJob .SCHEDULED_JOBS_INDEX , " ${monitor.id} -metadata" )
150
- val deleteResponse: DeleteResponse = client.suspendUntil { delete(deleteRequest, it) }
164
+ .setRefreshPolicy(WriteRequest .RefreshPolicy .IMMEDIATE )
165
+ try {
166
+ val deleteResponse: DeleteResponse = client.suspendUntil { delete(deleteRequest, it) }
167
+ log.debug(" Monitor metadata: ${deleteResponse.id} deletion result: ${deleteResponse.result} " )
168
+ } catch (e: Exception ) {
169
+ // we only log the error and don't fail the request because if monitor document has been deleted,
170
+ // we cannot retry based on this failure
171
+ log.error(" Failed to delete workflow metadata for monitor ${monitor.id} ." , e)
172
+ }
151
173
}
152
174
153
- private suspend fun deleteDocLevelMonitorQueriesAndIndices (monitor : Monitor ) {
154
- val clusterState = clusterService.state()
155
- val metadata = MonitorMetadataService .getMetadata(monitor)
156
- metadata?.sourceToQueryIndexMapping?.forEach { (_, queryIndex) ->
157
-
158
- val indicesExistsResponse: IndicesExistsResponse =
159
- client.suspendUntil {
160
- client.admin().indices().exists(IndicesExistsRequest (queryIndex), it)
175
+ suspend fun deleteDocLevelMonitorQueriesAndIndices (
176
+ client : Client ,
177
+ monitor : Monitor ,
178
+ monitorId : String ,
179
+ ) {
180
+ try {
181
+ val metadata = MonitorMetadataService .getMetadata(monitor)
182
+ metadata?.sourceToQueryIndexMapping?.forEach { (_, queryIndex) ->
183
+
184
+ val indicesExistsResponse: IndicesExistsResponse =
185
+ client.suspendUntil {
186
+ client.admin().indices().exists(IndicesExistsRequest (queryIndex), it)
187
+ }
188
+ if (indicesExistsResponse.isExists == false ) {
189
+ return
161
190
}
162
- if (indicesExistsResponse.isExists == false ) {
163
- return
164
- }
165
- // Check if there's any queries from other monitors in this queryIndex,
166
- // to avoid unnecessary doc deletion, if we could just delete index completely
167
- val searchResponse: SearchResponse = client.suspendUntil {
168
- search(
169
- SearchRequest (queryIndex).source(
170
- SearchSourceBuilder ()
171
- .size(0 )
172
- .query(
173
- QueryBuilders .boolQuery().mustNot(
174
- QueryBuilders .matchQuery(" monitor_id" , monitorId)
191
+ // Check if there's any queries from other monitors in this queryIndex,
192
+ // to avoid unnecessary doc deletion, if we could just delete index completely
193
+ val searchResponse: SearchResponse = client.suspendUntil {
194
+ search(
195
+ SearchRequest (queryIndex).source(
196
+ SearchSourceBuilder ()
197
+ .size(0 )
198
+ .query(
199
+ QueryBuilders .boolQuery().mustNot(
200
+ QueryBuilders .matchQuery(" monitor_id" , monitorId)
201
+ )
175
202
)
176
- )
177
- ).indicesOptions(IndicesOptions .LENIENT_EXPAND_OPEN_HIDDEN ),
178
- it
179
- )
180
- }
181
- if (searchResponse.hits.totalHits.value == 0L ) {
182
- val ack: AcknowledgedResponse = client.suspendUntil {
183
- client.admin().indices().delete(
184
- DeleteIndexRequest (queryIndex).indicesOptions(IndicesOptions .LENIENT_EXPAND_OPEN_HIDDEN ), it
203
+ ).indicesOptions(IndicesOptions .LENIENT_EXPAND_OPEN_HIDDEN ),
204
+ it
185
205
)
186
206
}
187
- if (ack.isAcknowledged == false ) {
188
- log.error(" Deletion of concrete queryIndex:$queryIndex is not ack'd!" )
189
- }
190
- } else {
191
- // Delete all queries added by this monitor
192
- val response: BulkByScrollResponse = suspendCoroutine { cont ->
193
- DeleteByQueryRequestBuilder (client, DeleteByQueryAction .INSTANCE )
194
- .source(queryIndex)
195
- .filter(QueryBuilders .matchQuery(" monitor_id" , monitorId))
196
- .refresh(true )
197
- .execute(
198
- object : ActionListener <BulkByScrollResponse > {
199
- override fun onResponse (response : BulkByScrollResponse ) = cont.resume(response)
200
- override fun onFailure (t : Exception ) = cont.resumeWithException(t)
201
- }
207
+ if (searchResponse.hits.totalHits.value == 0L ) {
208
+ val ack: AcknowledgedResponse = client.suspendUntil {
209
+ client.admin().indices().delete(
210
+ DeleteIndexRequest (queryIndex).indicesOptions(IndicesOptions .LENIENT_EXPAND_OPEN_HIDDEN ), it
202
211
)
212
+ }
213
+ if (ack.isAcknowledged == false ) {
214
+ log.error(" Deletion of concrete queryIndex:$queryIndex is not ack'd!" )
215
+ }
216
+ } else {
217
+ // Delete all queries added by this monitor
218
+ val response: BulkByScrollResponse = suspendCoroutine { cont ->
219
+ DeleteByQueryRequestBuilder (client, DeleteByQueryAction .INSTANCE )
220
+ .source(queryIndex)
221
+ .filter(QueryBuilders .matchQuery(" monitor_id" , monitorId))
222
+ .refresh(true )
223
+ .execute(
224
+ object : ActionListener <BulkByScrollResponse > {
225
+ override fun onResponse (response : BulkByScrollResponse ) = cont.resume(response)
226
+ override fun onFailure (t : Exception ) {
227
+ cont.resumeWithException(t)
228
+ }
229
+ }
230
+ )
231
+ }
203
232
}
204
233
}
234
+ } catch (e: Exception ) {
235
+ // we only log the error and don't fail the request because if monitor document has been deleted successfully,
236
+ // we cannot retry based on this failure
237
+ log.error(" Failed to delete workflow metadata for monitor ${monitor.id} ." , e)
205
238
}
206
239
}
207
240
}
0 commit comments