Skip to content

Commit efdf9a1

Browse files
authored
CP-308253: Task.destroy spans should no longer be orphaned (#6542)
Simplifies the logic of `exec_with_context` by letting the caller decide when the task is destroyed from the database. Adds helper function in `context.ml` to destroy and trace the destroy op correctly.
2 parents fa3488f + 63eef6f commit efdf9a1

File tree

3 files changed

+101
-37
lines changed

3 files changed

+101
-37
lines changed

ocaml/xapi/context.ml

Lines changed: 28 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -504,6 +504,34 @@ let get_client_ip context =
504504
let get_user_agent context =
505505
match context.origin with Internal -> None | Http (rq, _) -> rq.user_agent
506506

507+
let finally_destroy_context ~__context f =
508+
let tracing = __context.tracing in
509+
Xapi_stdext_pervasives.Pervasiveext.finally
510+
(fun () -> f __context)
511+
(fun () ->
512+
__context.tracing <- tracing ;
513+
destroy __context ;
514+
__context.tracing <- None
515+
)
516+
517+
let with_context ?http_other_config ?quiet ?subtask_of ?session_id ?database
518+
?task_in_database ?task_description ?origin task_name f =
519+
let __context =
520+
make ?http_other_config ?quiet ?subtask_of ?session_id ?database
521+
?task_in_database ?task_description ?origin task_name
522+
in
523+
finally_destroy_context ~__context f
524+
525+
let with_subcontext ~__context ?task_in_database task_name f =
526+
let __context = make_subcontext ~__context ?task_in_database task_name in
527+
finally_destroy_context ~__context f
528+
529+
let with_forwarded_task ?http_other_config ?session_id ?origin task_id f =
530+
let __context =
531+
from_forwarded_task ?http_other_config ?session_id ?origin task_id
532+
in
533+
finally_destroy_context ~__context f
534+
507535
let with_tracing ?originator ~__context name f =
508536
let open Tracing in
509537
let parent = __context.tracing in

ocaml/xapi/context.mli

Lines changed: 38 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -146,6 +146,44 @@ val complete_tracing : ?error:exn * Printexc.raw_backtrace -> t -> unit
146146

147147
val tracing_of : t -> Tracing.Span.t option
148148

149+
val finally_destroy_context : __context:t -> (t -> 'a) -> 'a
150+
(** [finally_destroy_context ~context f] executes [f ~__context] and then
151+
ensure [__context] is destroyed.*)
152+
153+
val with_context :
154+
?http_other_config:(string * string) list
155+
-> ?quiet:bool
156+
-> ?subtask_of:API.ref_task
157+
-> ?session_id:API.ref_session
158+
-> ?database:Xapi_database.Db_ref.t
159+
-> ?task_in_database:bool
160+
-> ?task_description:string
161+
-> ?origin:origin
162+
-> string
163+
-> (t -> 'a)
164+
-> 'a
165+
(** [with_context ?http_other_config ?quiet ?subtask_of ?session_id ?database
166+
?task_in_database ?task_description ?origin name f] creates a
167+
context [__context], executes [f ~__context] and then ensure [__context] is
168+
destroyed.*)
169+
170+
val with_subcontext :
171+
__context:t -> ?task_in_database:bool -> string -> (t -> 'a) -> 'a
172+
(** [with_subcontext ~__context ?task_in_database name] creates a subcontext
173+
[__context], executes [f ~__context] and then ensure `__context` is
174+
destroyed.*)
175+
176+
val with_forwarded_task :
177+
?http_other_config:(string * string) list
178+
-> ?session_id:API.ref_session
179+
-> ?origin:origin
180+
-> API.ref_task
181+
-> (t -> 'a)
182+
-> 'a
183+
(** [with_forwarded_task ?http_other_config ?session_id ?origin task f]
184+
creates a context form frowarded task [task], executes [f ~__context] and
185+
then ensure [__context] is destroyed.*)
186+
149187
val with_tracing :
150188
?originator:string -> __context:t -> string -> (t -> 'a) -> 'a
151189

ocaml/xapi/server_helpers.ml

Lines changed: 35 additions & 37 deletions
Original file line numberDiff line numberDiff line change
@@ -53,9 +53,10 @@ let parameter_count_mismatch_failure func expected received =
5353
API.response_of_failure Api_errors.message_parameter_count_mismatch
5454
[func; expected; received]
5555

56-
(** WARNING: the context is destroyed when execution is finished if the task is not forwarded, in database and not called asynchronous. *)
57-
let exec_with_context ~__context ~need_complete ?marshaller ?f_forward
58-
?(called_async = false) ?quiet f =
56+
(** WARNING: DOES NOT DESTROY the context when execution is finished. The
57+
caller must destroy it *)
58+
let exec_with_context ~__context ~need_complete ?marshaller ?f_forward ?quiet f
59+
=
5960
(* Execute fn f in specified __context, marshalling result with "marshaller" *)
6061
let exec () =
6162
(* NB:
@@ -95,23 +96,15 @@ let exec_with_context ~__context ~need_complete ?marshaller ?f_forward
9596
if need_complete then TaskHelper.failed ~__context e ;
9697
raise e
9798
in
98-
Locking_helpers.Thread_state.with_named_thread
99-
(TaskHelper.get_name ~__context) (Context.get_task_id __context) (fun () ->
100-
let client = Context.get_client __context in
101-
Debug.with_thread_associated ?client ?quiet
102-
(Context.string_of_task __context)
103-
(fun () ->
104-
(* CP-982: promote tracking debug line to info status *)
105-
if called_async then
106-
info "spawning a new thread to handle the current task%s"
107-
(Context.trackid ~with_brackets:true ~prefix:" " __context) ;
108-
Xapi_stdext_pervasives.Pervasiveext.finally exec (fun () ->
109-
if not called_async then Context.destroy __context
110-
(* else debug "nothing more to process for this thread" *)
111-
)
112-
)
113-
()
114-
)
99+
let@ () =
100+
Locking_helpers.Thread_state.with_named_thread
101+
(TaskHelper.get_name ~__context)
102+
(Context.get_task_id __context)
103+
in
104+
let client = Context.get_client __context in
105+
Debug.with_thread_associated ?client ?quiet
106+
(Context.string_of_task __context)
107+
exec ()
115108

116109
let dispatch_exn_wrapper f =
117110
try f ()
@@ -168,18 +161,22 @@ let do_dispatch ?session_id ?forward_op ?self:_ supports_async called_fn_name
168161

169162
let sync () =
170163
let need_complete = not (Context.forwarded_task __context) in
171-
exec_with_context ~__context ~need_complete ~called_async
172-
?f_forward:forward_op ~marshaller op_fn
164+
let@ __context = Context.finally_destroy_context ~__context in
165+
exec_with_context ~__context ~need_complete ?f_forward:forward_op
166+
~marshaller op_fn
173167
|> marshaller
174168
|> Rpc.success
175169
in
170+
176171
let async ~need_complete =
177172
(* Fork thread in which to execute async call *)
173+
info "spawning a new thread to handle the current task%s"
174+
(Context.trackid ~with_brackets:true ~prefix:" " __context) ;
178175
ignore
179176
(Thread.create
180177
(fun () ->
181-
exec_with_context ~__context ~need_complete ~called_async
182-
?f_forward:forward_op ~marshaller op_fn
178+
exec_with_context ~__context ~need_complete ?f_forward:forward_op
179+
~marshaller op_fn
183180
)
184181
()
185182
) ;
@@ -200,26 +197,27 @@ let do_dispatch ?session_id ?forward_op ?self:_ supports_async called_fn_name
200197
(* in the following functions, it is our responsibility to complete any tasks we create *)
201198
let exec_with_new_task ?http_other_config ?quiet ?subtask_of ?session_id
202199
?task_in_database ?task_description ?origin task_name f =
203-
exec_with_context ?quiet
204-
~__context:
205-
(Context.make ?http_other_config ?quiet ?subtask_of ?session_id
206-
?task_in_database ?task_description ?origin task_name
207-
) ~need_complete:true (fun ~__context -> f __context
200+
let@ __context =
201+
Context.with_context ?http_other_config ?quiet ?subtask_of ?session_id
202+
?task_in_database ?task_description ?origin task_name
203+
in
204+
exec_with_context ~__context ~need_complete:true (fun ~__context ->
205+
f __context
208206
)
209207

210208
let exec_with_forwarded_task ?http_other_config ?session_id ?origin task_id f =
211-
exec_with_context
212-
~__context:
213-
(Context.from_forwarded_task ?http_other_config ?session_id ?origin
214-
task_id
215-
) ~need_complete:true (fun ~__context -> f __context
209+
let@ __context =
210+
Context.with_forwarded_task ?http_other_config ?session_id ?origin task_id
211+
in
212+
exec_with_context ~__context ~need_complete:true (fun ~__context ->
213+
f __context
216214
)
217215

218216
let exec_with_subtask ~__context ?task_in_database task_name f =
219-
let subcontext =
220-
Context.make_subcontext ~__context ?task_in_database task_name
217+
let@ __context =
218+
Context.with_subcontext ~__context ?task_in_database task_name
221219
in
222-
exec_with_context ~__context:subcontext ~need_complete:true f
220+
exec_with_context ~__context ~need_complete:true f
223221

224222
let forward_extension ~__context rbac call =
225223
rbac __context (fun () -> Xapi_extensions.call_extension call)

0 commit comments

Comments
 (0)