1212 * GNU Lesser General Public License for more details.
1313 *)
1414
15- module D = Debug. Make (struct let name = " rate_limit " end )
15+ module D = Debug. Make (struct let name = __MODULE__ end )
1616
1717type t = {
1818 bucket : Token_bucket .t
1919 ; process_queue :
2020 (float * (unit -> unit )) Queue .t (* contains token cost and callback *)
2121 ; process_queue_lock : Mutex .t
2222 ; worker_thread_cond : Condition .t
23- ; should_terminate : bool ref (* signal termination to worker thread *)
23+ ; should_terminate : bool ref
24+ (* Signal termination to worker thread. The worker thread will
25+ process all remaining items in the queue before exiting. *)
2426 ; worker_thread : Thread .t
2527}
2628
@@ -52,30 +54,27 @@ let rec worker_loop ~bucket ~process_queue ~process_queue_lock
5254 ~should_terminate
5355
5456let create ~burst_size ~fill_rate =
55- match Token_bucket. create ~burst_size ~fill_rate with
56- | Some bucket ->
57- let process_queue = Queue. create () in
58- let process_queue_lock = Mutex. create () in
59- let worker_thread_cond = Condition. create () in
60- let should_terminate = ref false in
61- let worker_thread =
62- Thread. create
63- (fun () ->
64- worker_loop ~bucket ~process_queue ~process_queue_lock
65- ~worker_thread_cond ~should_terminate
66- )
67- ()
68- in
69- {
70- bucket
71- ; process_queue
72- ; process_queue_lock
73- ; worker_thread_cond
74- ; should_terminate
75- ; worker_thread
76- }
77- | None ->
78- raise (Failure " Invalid token bucket parameters" )
57+ let bucket = Token_bucket. create ~burst_size ~fill_rate in
58+ let process_queue = Queue. create () in
59+ let process_queue_lock = Mutex. create () in
60+ let worker_thread_cond = Condition. create () in
61+ let should_terminate = ref false in
62+ let worker_thread =
63+ Thread. create
64+ (fun () ->
65+ worker_loop ~bucket ~process_queue ~process_queue_lock
66+ ~worker_thread_cond ~should_terminate
67+ )
68+ ()
69+ in
70+ {
71+ bucket
72+ ; process_queue
73+ ; process_queue_lock
74+ ; worker_thread_cond
75+ ; should_terminate
76+ ; worker_thread
77+ }
7978
8079let delete data =
8180 with_lock data.process_queue_lock (fun () ->
@@ -84,11 +83,22 @@ let delete data =
8483 ) ;
8584 Thread. join data.worker_thread
8685
86+ let check_not_terminated should_terminate =
87+ if ! should_terminate then
88+ invalid_arg " Rate_limit: submit called on a deleted rate limiter"
89+
8790(* The callback should return quickly - if it is a longer task it is
8891 responsible for creating a thread to do the task *)
8992let submit_async
90- ({bucket; process_queue; process_queue_lock; worker_thread_cond; _} as _data )
91- ~callback amount =
93+ {
94+ bucket
95+ ; process_queue
96+ ; process_queue_lock
97+ ; worker_thread_cond
98+ ; should_terminate
99+ ; _
100+ } ~callback amount =
101+ check_not_terminated should_terminate ;
92102 let run_immediately =
93103 with_lock process_queue_lock (fun () ->
94104 let immediate =
@@ -104,10 +114,11 @@ let submit_async
104114 if run_immediately then
105115 callback ()
106116 else
107- D. debug " rate limiting sync call"
117+ D. debug " %s: rate limiting call" __FUNCTION__
108118
109119(* Block and execute on the same thread *)
110120let submit_sync bucket_data ~callback amount =
121+ check_not_terminated bucket_data.should_terminate ;
111122 let channel_opt =
112123 with_lock bucket_data.process_queue_lock (fun () ->
113124 if
0 commit comments