-
Notifications
You must be signed in to change notification settings - Fork 2
/
resource_pool.mli
133 lines (107 loc) · 5.75 KB
/
resource_pool.mli
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
(** External resource pools.
This module provides an abstraction for managing collections of resources.
One example use case is for managing a pool of database connections, where
instead of establishing a new connection each time you need one (which is
expensive), you can keep a pool of opened connections and reuse ones that
are free.
It also provides the capability of:
- specifying the maximum number of resources that the pool can manage
simultaneously,
- checking whether a resource is still valid before/after use, and
- performing cleanup logic before dropping a resource.
The following example illustrates how it is used with an imaginary
[Db] module:
{[
let uri = "postgresql://localhost:5432"
(* Create a database connection pool with max size of 10. *)
let pool =
Resource_pool.create 10
~dispose:(fun connection -> Db.close connection |> Lwt.return)
(fun () -> Db.connect uri |> Lwt.return)
(* Use the pool in queries. *)
let create_user name =
Resource_pool.use pool (fun connection ->
connection
|> Db.insert "users" [("name", name)]
|> Lwt.return
)
]}
Note that this is {e not} intended to keep a pool of system threads.
If you want to have such pool, consider using {!Lwt_preemptive}. *)
type 'a t
(** A pool containing elements of type ['a]. *)
val create :
?validate : ('a -> bool Lwt.t) ->
?check : (exn -> 'a -> bool Lwt.t) ->
?dispose : ('a -> unit Lwt.t) ->
int ->
(unit -> 'a Lwt.t) -> 'a t
(** [create n ?check ?validate ?dispose f] creates a new pool with at most
[n] elements. [f] is used to create a new pool element. Elements are
created on demand and re-used until disposed of. [f] may raise the
exception [Resource_invalid] to signal a failed resource creation. In this
case [use] will re-attempt to create the resource (according to
[creation_attempts]).
@param validate is called each time a pool element is accessed by {!use},
before the element is provided to {!use}'s callback. If
[validate element] resolves to [true] the element is considered valid and
is passed to the callback for use as-is. If [validate element] resolves
to [false] the tested pool element is passed to [dispose] then dropped,
with a new one is created to take [element]'s place in the pool.
@param check is called after the resolution of {!use}'s callback when the
resolution is a failed promise. [check element is_ok] must call [is_ok]
exactly once with [true] if [element] is still valid and [false]
otherwise. If [check] calls [is_ok false] then [dispose] will be run
on [element] and the element will not be returned to the pool.
@param dispose is used as described above and by {!clear} to dispose of
all elements in a pool. [dispose] is {b not} guaranteed to be called on
the elements in a pool when the pool is garbage collected. {!clear}
should be used if the elements of the pool need to be explicitly disposed
of. *)
(** set the maximum size of the pool *)
val set_max : 'a t -> int -> unit
(** exception to be thrown by the function supplied to [use] when a resource
is no longer valid and therefore to be disposed of;
[safe] determines whether it is safe to relaunch the function supplied to
[use]. Typically this refers to whether side-effects (that should not occur
a second time) have been effectuated before the exception was raised. *)
exception Resource_invalid of {safe : bool}
val use :
?creation_attempts:int ->
?usage_attempts:int ->
'a t -> ('a -> 'b Lwt.t) -> 'b Lwt.t
(** [use p f] requests one free element of the pool [p] and gives it to
the function [f]. The element is put back into the pool after the
promise created by [f] completes.
In case the resource supplied to [f] is no longer valid, [f] can throw a
[Resource_invalid] exception in which case the resource is disposed of.
The parameter [creation_attempts] (default: [1]) controls the number of
resource creation attempts that are made in case the creation function
raises the [Resource_invalid] exception.
The parameter [usage_attempts] (default: [1]) controls the number of
attempts that are made in case [f] raises the [Resource_invalid]
exception with [safe] set to true. After each attempt the resource is
disposed of.
In the case that [p] is exhausted and the maximum number of elements
is reached, [use] will wait until one becomes free. *)
val clear : 'a t -> unit Lwt.t
(** [clear p] will clear all elements in [p], calling the [dispose] function
associated with [p] on each of the cleared elements. Any elements from
[p] which are currently in use will be disposed of once they are
released.
The next call to [use p] after [clear p] guarantees a freshly created
pool element.
Disposals are performed sequentially in an undefined order. *)
exception Resource_limit_exceeded
val add : ?omit_max_check:bool -> 'a t -> 'a -> unit
(** By [add p c] you can add an existing resource element [c] to pool [p].
This function may raise a [Resource_limit_exceeded] exception. If
[omit_max_check] is [true] (default: [false]), then this exception will
not be raised. Instead the maximum number of resources might be exceeded
and more than [p.max] elements will be available to the user. *)
val wait_queue_length : _ t -> int
(** [wait_queue_length p] returns the number of {!use} requests currently
waiting for an element of the pool [p] to become available. *)
val wait_queue_delay : _ t -> float
(** [wait_queue_length p] returns the age of the oldest {!use} request
currently waiting for an element of the pool [p] to become available. *)