28
29:- module(threaded_throttle,
30 [ consume_threaded_throttle/2 31 , unconsume_threaded_throttle/2 32 , current_threaded_throttle_timeout/4 33 , set_threaded_throttle_timeout/4 34 , exit_threaded_throttle/2 35 ]). 36:- autoload(library(broadcast), [listen/3, unlisten/1, broadcast/1]). 37:- autoload(library(redis), [redis/3]). 38:- use_module(library(settings), [setting/4, setting/2]).
63:- setting(idle_timeout, number, env('THREADED_THROTTLE_IDLE_TIMEOUT', 5),
64 'Timeout in seconds for idling'). 65
66:- setting(wait_timeout, number, env('THREADED_THROTTLE_WAIT_TIMEOUT', 5),
67 'Timeout in seconds for waiting').
79consume_threaded_throttle(Key, Field) :-
80 81 82 key_field_alias(Key, Field, Alias),
83 listen(Alias, redis_consume(Key, Entry, _), consume(Key, Field, Entry)).
95unconsume_threaded_throttle(Key, Field) :-
96 key_field_alias(Key, Field, Alias),
97 unlisten(Alias).
98
99consume(Key, Field, Entry) :-
100 get_dict(Field, Entry, Value),
101 !,
102 103 104 create_thread(Key, Field, Thread),
105 thread_send_message(Thread, Value).
106consume(_, _, _).
107
111key_field_alias(Key, Field, Alias) :-
112 atomic_list_concat([threaded, Key, Field, throttle], '_', Alias).
113
114create_thread(Key, Field, Thread) :-
115 key_field_alias(Key, Field, Alias),
116 ( thread_property(Thread, alias(Alias))
117 -> true
118 ; thread_create(catch(throttle(Key, Field), quit, true), Thread,
119 [ alias(Alias),
120 detached(true)
121 ])
122 ).
123
124throttle(Key, Field) :-
125 ( redis(default, get(Key:Field), Value)
126 -> throttle_(Key, Field, Value)
127 ; throttle____(Key, Field)
128 ).
129
130throttle_(Key, Field, Value) :-
131 broadcast(threaded_throttle(up, Key, Field)),
132 throttle__(Key, Field, Value).
133
134throttle__(Key, Field, Value) :-
135 broadcast(threaded_throttle(adjust, Key, Field, Value)),
136 redis(default, set(Key:Field, Value), status(ok)),
137 throttle___(Key, Field, Value).
138
139throttle___(Key, Field, Value) :-
140 thread_self(Self),
141 current_threaded_throttle_timeout(idle, Key, Field, Timeout),
142 ( thread_get_message(Self, Value1, [timeout(Timeout)])
143 -> ( thread_peek_message(Self, _)
144 -> throttle___(Key, Field, Value)
145 ; ( Value == Value1
146 -> throttle___(Key, Field, Value1)
147 ; throttle__(Key, Field, Value1)
148 )
149 )
150 ; throttle____(Key, Field)
151 ).
152
153throttle____(Key, Field) :-
154 broadcast(threaded_throttle(down, Key, Field)),
155 thread_self(Self),
156 current_threaded_throttle_timeout(wait, Key, Field, Timeout),
157 ( thread_get_message(Self, Value, [timeout(Timeout)])
158 -> throttle_(Key, Field, Value)
159 ; throttle(Key, Field)
160 ).
161
162:- dynamic timeout/4.
185current_threaded_throttle_timeout(When, Key, Field, Timeout) :-
186 when(When, TimeoutSetting),
187 ( timeout(When, Key, Field, Timeout)
188 -> true
189 ; setting(TimeoutSetting, Timeout)
190 ).
211set_threaded_throttle_timeout(When, Key, Field, Timeout) :-
212 when(When, _),
213 retractall(timeout(When, Key, Field, _)),
214 assertz(timeout(When, Key, Field, Timeout)).
215
216when(idle, idle_timeout).
217when(wait, wait_timeout).
226exit_threaded_throttle(Key, Field) :-
227 key_field_alias(Key, Field, Alias),
228 ( thread_property(Thread, alias(Alias))
229 -> thread_signal(Thread, throw(quit))
230 ; true
231 )
Threaded Throttle
This module provides functionality for consuming throttle events from a Redis stream in a threaded manner. It allows for the creation of threads to handle throttle events, with configurable idle and wait timeouts. The module also provides predicates to set and retrieve timeout values for specific keys and fields.
Broadcast Events
The module broadcasts the following events:
threaded_throttle(up, Key, Field): A throttle event has been received for the specified Key and Field.threaded_throttle(adjust, Key, Field, Value): The throttle value has been adjusted for the specified Key and Field.threaded_throttle(down, Key, Field): The throttle event has completed for the specified Key and Field.