{"size": 8269, "ext": "scrbl", "max_stars_repo_path": "web-server-doc/web-server/scribblings/managers.scrbl", "max_stars_repo_name": "jessealama/web-server", "max_stars_repo_stars_event_min_datetime": "2015-01-21T08:11:58.000Z", "max_stars_repo_stars_event_max_datetime": "2022-03-20T08:28:39.000Z", "max_issues_repo_path": "web-server-doc/web-server/scribblings/managers.scrbl", "max_issues_repo_name": "jessealama/web-server", "max_issues_repo_issues_event_min_datetime": "2015-01-14T08:06:37.000Z", "max_issues_repo_issues_event_max_datetime": "2022-02-12T14:38:40.000Z", "max_forks_repo_path": "web-server-doc/web-server/scribblings/managers.scrbl", "max_forks_repo_name": "jessealama/web-server", "max_forks_repo_forks_event_min_datetime": "2015-03-05T15:07:36.000Z", "max_forks_repo_forks_event_max_datetime": "2021-07-30T18:59:25.000Z"}
{"max_stars_count": 82, "max_issues_count": 105, "max_forks_count": 37, "avg_line_length": 41.7626262626, "max_line_length": 97, "alphanum_fraction": 0.678074737}
#lang scribble/doc
@(require "web-server.rkt")

@title[#:tag "managers"]{Continuation Managers}

Since Racket servlets store their continuations on the server, they take
up memory on the server. Furthermore, garbage collection can not be used
to free this memory, because there are roots outside the system: users'
browsers, bookmarks, brains, and notebooks. Therefore, some other strategy
must be used if memory usage is to be controlled. This functionality is
pluggable through the @deftech{manager} interface.

@; ------------------------------------------------------------
@section[#:tag "manager"]{General}
@(require (for-label web-server/managers/manager)
          (for-label web-server/servlet/servlet-structs))

@defmodule[web-server/managers/manager]{

This module defines the manager interface. It is required by
the users and implementors of managers.

@defstruct[manager ([create-instance ((-> void) . -> . number?)]
                    [adjust-timeout! (number? number? . -> . void)]
                    [clear-continuations! (number? . -> . void)]
                    [continuation-store! (number? any/c 
                                                  (or/c false/c
                                                        (request? . -> . can-be-response?))
                                                  . -> . (list/c number? number?))]
                    [continuation-lookup (number? number? number? . -> . any/c)]
                    [continuation-peek (number? number? number? . -> . any/c)])]{
 @racket[create-instance] is called to initialize a instance, to hold the
 continuations of one servlet session. It is passed
 a function to call when the instance is expired. It runs the id of the
 instance.

 @racket[adjust-timeout!] is a to-be-deprecated function that takes an
 instance-id and a number. It is specific to the timeout-based manager
 and will be removed.

 @racket[clear-continuations!] expires all the continuations of an instance.

 @racket[continuation-store!] is given an instance-id, a continuation value,
 and a function to include in the exception thrown if the continuation is
 looked up and has been expired. The two numbers returned are a
 continuation-id and a nonce.

 @racket[continuation-lookup] finds the continuation value associated with
 the instance-id, continuation-id, and nonce triple it is given.
 
 @racket[continuation-peek] is identical to @racket[continuation-lookup] except that
 its use must not affect the resource management policy decisions on the instance or
 continuation accessed. It is intended to be used by debuggers and benchmarks.
}

@defstruct[(exn:fail:servlet-manager:no-instance exn:fail)
           ([expiration-handler 
             (or/c false/c
                   (request? . -> . can-be-response?))])]{
 This exception should be thrown by a manager when an instance is looked
 up that does not exist.
}

@defstruct[(exn:fail:servlet-manager:no-continuation exn:fail)
           ([expiration-handler 
             (or/c false/c
                   (request? . -> . can-be-response?))])]{
 This exception should be thrown by a manager when a continuation is
 looked up that does not exist.
}

}

@; ------------------------------------------------------------
@section[#:tag "none"]{No Continuations}
@(require (for-label web-server/managers/none))

@defmodule[web-server/managers/none]{

This module defines a manager constructor:

@defproc[(create-none-manager 
          (instance-expiration-handler 
           (or/c false/c
                 (request? . -> . can-be-response?))))
         manager?]{
 This manager does not actually store any continuation or instance data.
 You could use it if you know your servlet does not use the continuation
 capturing functions and want the server to not allocate meta-data
 structures for each instance.
 
 If you @emph{do} use a continuation capturing function, the continuation is
 simply not stored. If the URL is visited, the @racket[instance-expiration-handler]
 is called with the request.
}

If you are considering using this manager, also consider using the
Web Language. (See @secref["stateless"].)

}

@; ------------------------------------------------------------
@section[#:tag "timeouts"]{Timeouts}
@(require (for-label web-server/managers/timeouts))

@defmodule[web-server/managers/timeouts]{

This module defines a manager constructor:

@defproc[(create-timeout-manager 
          [instance-exp-handler 
           (or/c false/c
                 (request? . -> . can-be-response?))]
          [instance-timeout number?]
          [continuation-timeout number?])
         manager?]{
 Instances managed by this manager will be expired @racket[instance-timeout]
 seconds after the last time it is accessed. If an expired instance is
 looked up, the @racket[exn:fail:servlet-manager:no-instance] exception
 is thrown with @racket[instance-exp-handler] as the expiration handler.

 Continuations managed by this manager will be expired @racket[continuation-timeout]
 seconds after the last time it is accessed. If an expired continuation is looked
 up, the @racket[exn:fail:servlet-manager:no-continuation] exception
 is thrown with @racket[instance-exp-handler] as the expiration handler, if
 no expiration-handler was passed to @racket[continuation-store!].

 @racket[adjust-timeout!] corresponds to @racket[reset-timer!] on the timer
 responsible for the servlet instance.
}

This manager has been found to be... problematic... in large-scale
deployments of the @web-server .

}

@; ------------------------------------------------------------
@section[#:tag "lru"]{LRU}
@(require (for-label web-server/managers/lru))

@defmodule[web-server/managers/lru]{

This module defines a manager constructor:

@defproc[(create-LRU-manager
          [instance-expiration-handler 
           (or/c false/c
                 (request? . -> . can-be-response?))]
          [check-interval integer?]
          [collect-interval integer?]
          [collect? (-> boolean?)]
          [#:initial-count initial-count integer? 1]
          [#:inform-p inform-p (integer? . -> . void) (lambda _ (void))])
         manager?]{
 Instances managed by this manager will be expired if there are no
 continuations associated with them, after the instance is unlocked.
 If an expired instance is looked up, the
 @racket[exn:fail:servlet-manager:no-instance] exception
 is thrown with @racket[instance-exp-handler] as the expiration handler.

 Continuations managed by this manager are given a "Life Count" of
 @racket[initial-count] initially. If an expired continuation is looked
 up, the @racket[exn:fail:servlet-manager:no-continuation] exception
 is thrown with @racket[instance-exp-handler] as the expiration handler, if
 no expiration-handler was passed to @racket[continuation-store!].

 Every @racket[check-interval] seconds @racket[collect?] is called to determine
 if the collection routine should be run. Every @racket[collect-interval] seconds
 the collection routine is run.

 Every time the collection routine runs, the "Life Count" of every
 continuation is decremented by @racket[1]. If a continuation's count
 reaches @racket[0], it is expired. The @racket[inform-p] function
 is called if any continuations are expired, with the number of
 continuations expired.
}
                  
The recommended usage of this manager is codified as the following function:

@defproc[(make-threshold-LRU-manager 
          [instance-expiration-handler 
           (or/c false/c
                 (request? . -> . can-be-response?))]
          [memory-threshold number?])
         manager?]{
 This creates an LRU manager with the following behavior:
 The memory limit is set to @racket[memory-threshold] bytes. Continuations start with @racket[24]
 life points. Life points are deducted at the rate of one every @racket[10] minutes, or one
 every @racket[5] seconds when the memory limit is exceeded. Hence the maximum life time for
 a continuation is @racket[4] hours, and the minimum is @racket[2] minutes.
 
 If the load on the server spikes---as indicated by memory usage---the server will quickly expire
 continuations, until the memory is back under control. If the load
 stays low, it will still efficiently expire old continuations.
}
 
}
