What does "No instance for id: 1" mean in the Racket webserver?

Over the past few years I've been getting deeper into the Racket ecosystem, and encountering more obscure problems.

Today I seem to be misusing the Racket webserver and failing to understand a message.

I'm using the Racket webserver to manage an interaction between multiple clents.
Sometimes it works as planned, and sometimes I get the message "No instance for id: 1" with a backtrace containing none of my code.

What are these units? What are their instances? How does the web-server use them? What is an id in this context?

I got this message most recently after I connected to the server from Montreal, and then two friends connected (from Florida and Saskatchewan) and could not get in because of this message. After that I could not connect again either, getting the same message.

Does this message have something to do with concurrency?

Is there relevant documentation somewhere?

My code is at http://topoi.pooq.com/maze-source/ but I'm not asking you to debug my code (it is still a mess needing reorganisation); I'm asking for insight into the words used in the error message I get and understanding what the message means in the context of the web-server. Sorry: the documentation in the .mt3 files in that directory there is raw brain-dump. I'm intending to clean it up and reorganise it, but I'm deferring that until I'm sure the code it's describing isn't conceptually brain-dead.

-- hendrik

Since continuations take up memory (and they can't be garbage collected),
the web-server has something called "continuation managers" that
determine how long continuations are stored.

The documentation is sparse on details, but an instance holds the
continuations of one servlet session:

https://docs.racket-lang.org/web-server/servlet.html#(part._managers)

Could the reason for the error, you saw, be related to timeouts?

I notice the comment in the docs for create-timeout-manager:

This manager has been found to be... problematic... in large-scale deployments of the Web Server .

Since continuations take up memory (and they can't be garbage collected),
the web-server has something called "continuation managers" that
determine how long continuations are stored.

The documentation is sparse on details, but an instance holds the
continuations of one servlet session:

2 Stateful Servlets

Could the reason for the error, you saw, be related to timeouts?

I suppose it is possible. However, I specify #:stateless? #t so that continuations are not passed to and from the client.
I also specify #:connection-close? #t so that each user action can be a separate http request, and the connections are dropped ready for the next action, possibly by another user.

This is how I start the servlet.

(serve/servlet start
#:connection-close? #t ; to release the port for another player.
#:stateless? #t
#| not really; this means that the Racket webserver
doesn't do strange things to maintain a state.
>#
#:listen-ip #f ; listen on all available incoming ports;
; without specifying #f here, it will listen only on 127.0.0.1 (the default)
; good for testing an insecure webserver, but likely not for production.
#:port the-game-port
#:launch-browser? #f
#:banner? #f
#:servlet-path "/4d"
)
; documented in section 1.2.2 Full API of 1 Running Web Servlets

I notice the comment in the docs for create-timeout-manager:

This manager has been found to be... problematic... in large-scale deployments of the Web Server .

I do not use timeouts myself.
Is the timeout manager still used to manage continuations even if I specify #:stateless? #t ?

-- hendrik

I have never experimented with stateless servlets, but I believe the point of
stateless servlets is that any continuations can be explicitly represented
as serializable data. The job of the continuation manager is to decide
when (or if at all) continuations are to be moved from memory to disk.

The default manager for serve/servlet is:

manager : manager? = (make-threshold-LRU-manager #f (* 128 1024 1024))

The docs say:

This creates an LRU manager with the following behavior: The memory limit is set to memory-threshold bytes. Continuations start with 24 life points. Life points are deducted at the rate of one every 10 minutes, or one every 5 seconds when the memory limit is exceeded. Hence the maximum life time for a continuation is 4 hours, and the minimum is 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.

I have never experimented with stateless servlets, but I believe the point of
stateless servlets is that any continuations can be explicitly represented
as serializable data. The job of the continuation manager is to decide
when (or if at all) continuations are to be moved from memory to disk.

So the point of stateless servers is that a continuation is serialised
and the serialised version is stored somewhere or sent to the client as
part of a response so that the client will send back the continuaton and
go on from where the client's previous action left off? It's that the
server doesn't need to store state?

I see.

That's exactly backwards to the way I wanted, and backwards from the way
I understood it.

So a stateful server doesn't take any part in passing serialised
continuations back and forth between the client and server.

So it seems I want a stateful server, not a stateless one!

One where the code that's calling on the Racket web library contains
the state, and the actual webserver package has nothing to do with it.

I'll try to flip the switch the other way, and see if it works better,

Of course there is state either way. It's just a matter of where the state is stored and what code does what with it.

-- hendrik