Documentation ¶
Overview ¶
Package rp ("resource protector") provides functions that help control access to some limited resource.
You first create a Protector, and then make Request()s for tokens. Requests give you Receipts that you use to WaitUntilGranted() to know when a request succeeded and you "have" the tokens. You can now use whatever the actual resource is. Once you're done with it you Release() the request so that some other request can "use" those tokens.
The Protector offers these guarantees:
# The maximum number of requests that are granted and in play at any one time is the lesser of the Protector's maxSimultaneous value or the return value of the Protector's AvailabilityCallback (if set). # Requests (and the calling of the AvailabilityCallback, if set) are granted with at least a delay of the Protector's delayBetween value between each grant (or call). # If clients fail to release granted requests, they will be automatically released. import "github.com/VertebrateResequencing/wr/rp" p := rp.New("irods", 2 * time.Second, 20, 5 * time.Minute) // now every time you want use the protected resource, make a request: receipt, err := p.Request(1) p.WaitUntilGranted(receipt) // now use the irods resource; if using it will take longer than 5mins, // arrange to call p.Touch(receipt) every, say, 2.5mins until you're done // once you've finished using the resource: p.Release(receipt)
Index ¶
- Constants
- type AvailabilityCallback
- type Error
- type Protector
- func (p *Protector) Granted(receipt Receipt) (granted, keepChecking bool)
- func (p *Protector) Release(receipt Receipt)
- func (p *Protector) ReleaseAfter(receipt Receipt, delay time.Duration)
- func (p *Protector) Request(numTokens int) (Receipt, error)
- func (p *Protector) SetAvailabilityCallback(callback AvailabilityCallback)
- func (p *Protector) Shutdown()
- func (p *Protector) Touch(receipts ...Receipt)
- func (p *Protector) WaitUntilGranted(receipt Receipt, timeout ...time.Duration) bool
- type Receipt
Constants ¶
const ( ErrOverMaximumTokens = "more tokens requested than can ever be supplied" ErrShutDown = "the protector has been shut down" )
rp has some typical errors
#nosec
Variables ¶
This section is empty.
Functions ¶
This section is empty.
Types ¶
type AvailabilityCallback ¶
type AvailabilityCallback func() (numTokens int)
AvailabilityCallback is used as a callback to know how many tokens are currently available for use.
type Error ¶
type Error struct { Protector string // the protector's Name Op string // name of the method Request Receipt // the request's id Err string // one of our Err constants }
Error records an error and the operation, request and protector that caused it.
type Protector ¶
type Protector struct { Name string // Name of the resource being protected. // contains filtered or unexported fields }
Protector struct is used to Protect a particular resource by granting tokens tokens when the resource has capacity.
func New ¶
func New(name string, delayBetween time.Duration, maxSimultaneous int, releaseTimeout time.Duration) *Protector
New creates a new Protector. The name is for your benefit, describing the resource you're protecting.
delayBetween defines the minimum delay between the granting of the tokens for each Request(). This would be used to avoid spamming your resource with too high a frequency of accesses.
maxSimultaneous defines the maximum number of tokens that can be in use concurrently. This would be used to avoid overloading your resource with too much usage.
releaseTimeout is the time after which granted tokens are automatically released for use by other requests if the receiver fails to Touch() or Release() before then (so that a client that starts using tokens but then dies unexpectedly doesn't hold on to those tokens forever).
func (*Protector) Granted ¶
Granted is an alternative to WaitUntilGranted(). Instead of blocking until the request corresponding to the given receipt is granted, you can call Granted() periodically until the first bool return value is true.
Note that if you call Granted after more time than the releaseTimeout supplied to New() has passed since you made the Request(), the request will already have been released, and this function will return false. There is now no point in checking Granted() any more since it will never become true, hence the second bool will be false in this case. (You will also get double false if you supply an invalid Receipt.)
func (*Protector) Release ¶
Release will release the tokens of a granted Request(), for use by any other requests. You should always call this when you're done using a resource (unless you use ReleaseAfter() instead).
func (*Protector) ReleaseAfter ¶
ReleaseAfter is a convenience function that calls Release() after the given delay, but returns immediately.
func (*Protector) Request ¶
Request lets you request that a desired number of tokens be granted to you for use.
You immediately get back a Receipt, which you should supply to WaitUntilGranted(), then to Touch() periodically until you're no longer using the resource, then finally to Release().
func (*Protector) SetAvailabilityCallback ¶
func (p *Protector) SetAvailabilityCallback(callback AvailabilityCallback)
SetAvailabilityCallback sets a callback that will be called whenever the Protector checks to see if Request()s can be fulfilled.
The callback should do some kind of check on the resource to see how busy it is, and return a number between 0 (block any additional usage of the resource) and the maxSimultaneous value provided to New() (higher values will be of no benefit).
The callback will only be called at most every delayBetween value supplied to New(), so if checking the resource is an expensive operation, be sure to set that value appropriately high. (Or do appropriate caching of the busyness on your end.)
NB: You'd only set this callback if you have unprotected access to your resource that you need the Protector to take in to account.
func (*Protector) Shutdown ¶
func (p *Protector) Shutdown()
Shutdown will make subsequent Request(), WaitUntilGranted() and Granted() calls fail. Any currently granted requests will be released. Any ungranted requests will be forgotten about.
func (*Protector) Touch ¶
Touch for a request (identified by the given receipt) prevents it timing out and releasing the granted tokens. You should call this periodically after WaitUntilGranted() for the same receipt.
Rather than have a goroutine for each of your requests that you use to periodically touch, you could instead have a single goroutine that touches all your granted and active requests. Hence this method can take more than one receipt.
func (*Protector) WaitUntilGranted ¶
WaitUntilGranted will block until the request corresponding to the given Receipt has been granted its tokens, whereupon you can start using the protected resource.
If you call this after more time than the releaseTimeout supplied to New() has passed since you made the Request(), the request will already have been released, and this function will return false: do not use the resources in that case! (You will also get false if you supply an invalid Receipt.)
You can optionally supply a timeout. If it ends up taking longer that this duration the request will be cancelled, the receipt will no longer be useful, and this function will return false.