1212import org .elasticsearch .ExceptionsHelper ;
1313import org .elasticsearch .ResourceNotFoundException ;
1414import org .elasticsearch .action .ActionListener ;
15+ import org .elasticsearch .action .update .UpdateResponse ;
1516import org .elasticsearch .cluster .node .DiscoveryNode ;
1617import org .elasticsearch .cluster .service .ClusterService ;
1718import org .elasticsearch .common .TriFunction ;
@@ -86,23 +87,10 @@ public void retrieveResult(GetAsyncResultRequest request, ActionListener<Respons
8687 // EQL doesn't store initial or intermediate results so we only need to update expiration time in store for only in case of
8788 // async search
8889 if (updateInitialResultsInStore & expirationTime > 0 ) {
89- store . updateExpirationTime (
90- searchId . getDocId () ,
90+ updateExpirationTime (
91+ searchId ,
9192 expirationTime ,
92- ActionListener .wrap (p -> getSearchResponseFromTask (searchId , request , nowInMillis , expirationTime , listener ), exc -> {
93- RestStatus status = ExceptionsHelper .status (ExceptionsHelper .unwrapCause (exc ));
94- if (status != RestStatus .NOT_FOUND ) {
95- logger .error (
96- () -> format ("failed to update expiration time for async-search [%s]" , searchId .getEncoded ()),
97- exc
98- );
99- listener .onFailure (exc );
100- } else {
101- // the async search document or its index is not found.
102- // That can happen if an invalid/deleted search id is provided.
103- listener .onFailure (new ResourceNotFoundException (searchId .getEncoded ()));
104- }
105- })
93+ listener .delegateFailure ((l , unused ) -> getSearchResponseFromTask (searchId , request , nowInMillis , expirationTime , l ))
10694 );
10795 } else {
10896 getSearchResponseFromTask (searchId , request , nowInMillis , expirationTime , listener );
@@ -122,45 +110,63 @@ private void getSearchResponseFromTask(
122110 try {
123111 final Task task = store .getTaskAndCheckAuthentication (taskManager , searchId , asyncTaskClass );
124112 if (task == null || (updateInitialResultsInStore && task .isCancelled ())) {
125- getSearchResponseFromIndex (searchId , request , nowInMillis , listener );
113+ getSearchResponseFromIndexAndUpdateExpiration (searchId , request , nowInMillis , expirationTimeMillis , listener );
126114 return ;
127115 }
128116
129117 if (expirationTimeMillis != -1 ) {
130118 task .setExpirationTime (expirationTimeMillis );
131119 }
132- boolean added = addCompletionListener .apply (
133- task ,
134- listener .delegateFailure ((l , response ) -> sendFinalResponse (request , response , nowInMillis , l )),
135- request .getWaitForCompletionTimeout ()
136- );
120+ boolean added = addCompletionListener .apply (task , listener .delegateFailure ((l , response ) -> {
121+ // If the task expiration is updated after the document was created with an earlier expiration time,
122+ // we should TRY to update the document's expiration time here.
123+ if (updateInitialResultsInStore == false && expirationTimeMillis != -1 ) {
124+ store .updateExpirationTime (
125+ searchId .getDocId (),
126+ expirationTimeMillis ,
127+ ActionListener .running (() -> sendFinalResponse (request , response , nowInMillis , l ))
128+ );
129+ } else {
130+ sendFinalResponse (request , response , nowInMillis , l );
131+ }
132+ }), request .getWaitForCompletionTimeout ());
137133 if (added == false ) {
138134 // the task must have completed, since we cannot add a completion listener
139135 assert store .getTaskAndCheckAuthentication (taskManager , searchId , asyncTaskClass ) == null ;
140- getSearchResponseFromIndex (searchId , request , nowInMillis , listener );
136+ getSearchResponseFromIndexAndUpdateExpiration (searchId , request , nowInMillis , expirationTimeMillis , listener );
141137 }
142138 } catch (Exception exc ) {
143139 listener .onFailure (exc );
144140 }
145141 }
146142
147- private void getSearchResponseFromIndex (
143+ private void getSearchResponseFromIndexAndUpdateExpiration (
148144 AsyncExecutionId searchId ,
149145 GetAsyncResultRequest request ,
150146 long nowInMillis ,
151- ActionListener <Response > listener
147+ long expirationTime ,
148+ ActionListener <Response > outListener
152149 ) {
153- store .getResponse (searchId , true , listener .delegateFailure ((l , response ) -> {
154- try {
155- sendFinalResponse (request , response , nowInMillis , l );
156- } finally {
157- if (response instanceof StoredAsyncResponse <?> storedAsyncResponse
158- && storedAsyncResponse .getResponse () instanceof RefCounted refCounted ) {
159- refCounted .decRef ();
150+ var updateListener = outListener .delegateFailure ((listener , unused ) -> {
151+ store .getResponse (searchId , true , listener .delegateFailure ((l , response ) -> {
152+ try {
153+ sendFinalResponse (request , response , nowInMillis , l );
154+ } finally {
155+ if (response instanceof StoredAsyncResponse <?> storedAsyncResponse
156+ && storedAsyncResponse .getResponse () instanceof RefCounted refCounted ) {
157+ refCounted .decRef ();
158+ }
160159 }
161- }
162160
163- }));
161+ }));
162+ });
163+ // If updateInitialResultsInStore=false, we can't update expiration while the task is running since the document doesn't exist yet.
164+ // So let's update the expiration here when the task has been completed.
165+ if (updateInitialResultsInStore == false && expirationTime != -1 ) {
166+ updateExpirationTime (searchId , expirationTime , updateListener .map (unused -> null ));
167+ } else {
168+ updateListener .onResponse (null );
169+ }
164170 }
165171
166172 private void sendFinalResponse (GetAsyncResultRequest request , Response response , long nowInMillis , ActionListener <Response > listener ) {
@@ -172,4 +178,18 @@ private void sendFinalResponse(GetAsyncResultRequest request, Response response,
172178
173179 listener .onResponse (response );
174180 }
181+
182+ private void updateExpirationTime (AsyncExecutionId searchId , long expirationTime , ActionListener <UpdateResponse > listener ) {
183+ store .updateExpirationTime (searchId .getDocId (), expirationTime , listener .delegateResponse ((l , e ) -> {
184+ RestStatus status = ExceptionsHelper .status (ExceptionsHelper .unwrapCause (e ));
185+ if (status != RestStatus .NOT_FOUND ) {
186+ logger .error (() -> format ("failed to update expiration time for async-search [%s]" , searchId .getEncoded ()), e );
187+ l .onFailure (e );
188+ } else {
189+ // the async search document or its index is not found.
190+ // That can happen if an invalid/deleted search id is provided.
191+ l .onFailure (new ResourceNotFoundException (searchId .getEncoded ()));
192+ }
193+ }));
194+ }
175195}
0 commit comments