Re: [racket-users] Web server hits "Sorry, this page has expired. Please go back."

2018-10-17 Thread Luke Whittlesey
Interesting conversation.. I want to add that #lang web-server does have
file-boxes (
https://docs.racket-lang.org/web-server/stateless.html?q=web-server#%28part._lang%2Ffile-box%29)
for when one might want to preserve data like you would in the store. To
run across multiple machines I would imagine one could also write a
file-box-ish approach to a database, but I haven't gotten there yet.
I think one of the exciting aspects for me regarding stateless
continuations is the idea of running on multiple servers with the only
shared state being cookies and file-boxes. I imagine being able to easily
scale with something like Amazon Lambda. Although I haven't tried that yet
either, so maybe there are roadblocks there.

On Sun, Oct 14, 2018 at 7:55 PM George Neuner  wrote:

> Hi Philip,
>
> Sorry for the delay in responding ... busy day.
>
>
> On 10/14/2018 7:09 AM, Philip McGrath wrote:
>
> On Sun, Oct 14, 2018 at 5:30 AM George Neuner 
> wrote:
>
>> You are absolutely correct that in typical usage globals are not closed
>> over ... normally they are considered mutable shared "communication"
>> state.
>>
>> However, I was speaking more generally:  to be persisted long duration,
>> and be made portable across separate runtime instances, the continuation
>> must close over AND deep copy ANY VALUE the current call chain references.
>> You don't (necessarily) want to restart the continuation a week later, on a
>> different machine, with different values than when it started.
>>
>
> I am definitely not an expert on continuations or PL generally, so I could
> be very wrong. My understanding, though, has been that continuations not
> closing over non-local variables is a property of continuations in general:
> not only in a web context, and not only of the serializable continuations
> from `#lang web-server`. (I used those in my example just because it is
> easy to see what values they do in fact close over.)
>
>
> In the most basic form, the continuation is just "what to do next" - e.g.,
> a pointer to the next code to be executed.  That is [more or less] all that
> is required for a local (within a function) escape continuation because
> [barring stack corruption] all of the EC's stack context is guaranteed to
> exist if/when the continuation is invoked, and that state is needed anyway
> because the program will continue on regardless of how it leaves the scope
> of the EC.
>
> For a non-local EC, you need to return to the stack frame that was current
> when the continuation was created [the rest of the stack can be
> discarded].  In any case, an EC can very compact - just a couple of
> pointers.
>
> [Aside: a Lisp-style exception requires that the entire call stack be kept
> until you know where execution will continue.  You need to return to the
> EC's call frame (to find the exception handler), but Lisp allows exceptions
> to introspect/modify the environment and then to return control to the
> point of the exception (where the intrinsic EC was invoked).  Scheme
> doesn't have this capability.]
>
>
> General continuations - such as can implement coroutines - need to capture
> much more state.  The entire stack state of the current function call chain
> at the point where the continuation is created must be preserved in order
> to reenter the continuation.
> [this is where stateful and stateless part company - more below]
>
>
> Winding continuations are an extension of general continuations to the
> requirements of dynamic-wind.  In addition to whatever is required for a
> general continuation, a winding continuation has preamble code that must be
> executed whenever a continuation enters the winding scope, and postamble
> code to be executed whenever (and how ever) execution leaves the winding
> scope.
>
>
> The long winded point here is that continuations have no canon
> implementation - if you want more functionality from them, you need to
> capture/preserve more state.
>
>
>
> The web-server is multi-threaded, and the stack state of each thread is
> unique - so for each thread in which a continuation is created in the
> stateful server, the thread's call stack must be preserved.
>
> The stateless server is a different case.  CPS code doesn't use a call
> stack ... or rather its "stack" only ever contains one useful frame - the
> current one.  So there's only one call frame per thread that needs to be
> preserved rather than a (maybe large) stack of them.  This is why stateless
> server continuations - in general - use much less memory than stateful
> server continuations.
>
> [The above is a bit simplistic because Scheme supports nested functions
> with non-local variable access.  [Scheme also supports 1st class closures
> based on nested functions, but that is not what this is about.]   To
> support non-local access without a stack, CPS code needs to construct
> shared environments on the fly as the program executes to communicate
> values from producers to consumers, and these environments (where
> 

Re: [racket-users] Web server hits "Sorry, this page has expired. Please go back."

2018-10-14 Thread George Neuner

Hi Philip,

Sorry for the delay in responding ... busy day.


On 10/14/2018 7:09 AM, Philip McGrath wrote:
On Sun, Oct 14, 2018 at 5:30 AM George Neuner > wrote:


You are absolutely correct that in typical usage globals are not
closed over ... normally they are considered mutable shared
"communication" state.

However, I was speaking more generally:  to be persisted long
duration, and be made portable across separate runtime instances,
the continuation must close over AND deep copy ANY VALUE the
current call chain references.  You don't (necessarily) want to
restart the continuation a week later, on a different machine,
with different values than when it started.


I am definitely not an expert on continuations or PL generally, so I 
could be very wrong. My understanding, though, has been that 
continuations not closing over non-local variables is a property of 
continuations in general: not only in a web context, and not only of 
the serializable continuations from `#lang web-server`. (I used those 
in my example just because it is easy to see what values they do in 
fact close over.)


In the most basic form, the continuation is just "what to do next" - 
e.g., a pointer to the next code to be executed.  That is [more or less] 
all that is required for a local (within a function) escape continuation 
because [barring stack corruption] all of the EC's stack context is 
guaranteed to exist if/when the continuation is invoked, and that state 
is needed anyway because the program will continue on regardless of how 
it leaves the scope of the EC.


For a non-local EC, you need to return to the stack frame that was 
current when the continuation was created [the rest of the stack can be 
discarded].  In any case, an EC can very compact - just a couple of 
pointers.


[Aside: a Lisp-style exception requires that the entire call stack be 
kept until you know where execution will continue.  You need to return 
to the EC's call frame (to find the exception handler), but Lisp allows 
exceptions to introspect/modify the environment and then to return 
control to the point of the exception (where the intrinsic EC was 
invoked).  Scheme doesn't have this capability.]



General continuations - such as can implement coroutines - need to 
capture much more state.  The entire stack state of the current function 
call chain at the point where the continuation is created must be 
preserved in order to reenter the continuation.

[this is where stateful and stateless part company - more below]


Winding continuations are an extension of general continuations to the 
requirements of dynamic-wind.  In addition to whatever is required for a 
general continuation, a winding continuation has preamble code that must 
be executed whenever a continuation enters the winding scope, and 
postamble code to be executed whenever (and how ever) execution leaves 
the winding scope.



The long winded point here is that continuations have no canon 
implementation - if you want more functionality from them, you need to 
capture/preserve more state.




The web-server is multi-threaded, and the stack state of each thread is 
unique - so for each thread in which a continuation is created in the 
stateful server, the thread's call stack must be preserved.


The stateless server is a different case.  CPS code doesn't use a call 
stack ... or rather its "stack" only ever contains one useful frame - 
the current one.  So there's only one call frame per thread that needs 
to be preserved rather than a (maybe large) stack of them.  This is why 
stateless server continuations - in general - use much less memory than 
stateful server continuations.


[The above is a bit simplistic because Scheme supports nested functions 
with non-local variable access.  [Scheme also supports 1st class 
closures based on nested functions, but that is not what this is 
about.]   To support non-local access without a stack, CPS code needs to 
construct shared environments on the fly as the program executes to 
communicate values from producers to consumers, and these environments 
(where applicable) also must be part of saved continuation state.  
Environment construction is similar to, but not the same as closure 
conversion:  as with closures the code must be compiled to expect the 
variable(s) in the external environment block rather than in the call 
frame - but unlike closures, a new environment must be constructed each 
time a given producer needs to communicate with consumers.


The alternative to these "environments" is to pass everything by 
argument - but doing that in CPS quickly leads to functions with huge 
argument lists, and to functions having many "pass-thru" arguments that 
they don't use.


A related procedure done with stack-based implementations is sometimes 
referred to as "stack flattening".  When a function high in the call 
chain must communicate with functions lower down in the 

Re: [racket-users] Web server hits "Sorry, this page has expired. Please go back."

2018-10-14 Thread Hendrik Boom
On Sun, Oct 14, 2018 at 07:09:38AM -0400, Philip McGrath wrote:
> On Sun, Oct 14, 2018 at 5:30 AM George Neuner  wrote:
> 
> > You are absolutely correct that in typical usage globals are not closed
> > over ... normally they are considered mutable shared "communication"
> > state.
> >
> > However, I was speaking more generally:  to be persisted long duration,
> > and be made portable across separate runtime instances, the continuation
> > must close over AND deep copy ANY VALUE the current call chain references.
> > You don't (necessarily) want to restart the continuation a week later, on a
> > different machine, with different values than when it started.
> >
> 
> I am definitely not an expert on continuations or PL generally, so I could
> be very wrong. My understanding, though, has been that continuations not
> closing over non-local variables is a property of continuations in general:
> not only in a web context, and not only of the serializable continuations
> from `#lang web-server`. (I used those in my example just because it is
> easy to see what values they do in fact close over.)
> 
> I remember reading in an old mailing list thread (
> https://groups.google.com/d/topic/racket-users/mHiVPuYPNiE/discussion), not
> in the context of web programming:
> 
> On Sep 5, 2012, at 5:39 PM, Harry Spier wrote:
> 
> > Is there a way to save any  valid continuation and be guaranteed that
> > nothing that happens in the program between the time the continuation was
> > saved and the time the saved continuation was invoked will alter the
> > results of invoking the continuation.
> >
> On Wednesday, September 5, 2012 at 5:52:31 PM UTC-4, Matthias Felleisen
> wrote:
> >
> > No. A continuation represents the __control state__ of a program NOT the
> > __memory state__.  Since your program can change the memory state while the
> > continuation is stored, and since the continuation may reference the memory
> > state once it is thrown, there is no way to guarantee the exact same
> > outcome in general.
> >
> > People have experimented with call-with-current-store so that they can
> > capture the store and re-install it, especially for continuation launches.
> > The SML/NSJ debugger worked like this but in general it is not practical.
> >
> 
> I definitely understand how it could be useful to have something that did
> close over and deep copy any value the current call chain references! But
> my understanding (which, again, could be flawed) is that continuations
> don't do that.

Nor should they!  I'm a proponent of almost-functional programming, in 
which you use state changes occasionally for efficiency.  For example, a 
continuation might have the task of answering a particuar question, and 
it's useful for it to be able to chack a stateful registry to check if 
something else in the wider program has already announced the 
answer to that that question.

-- hendrik

-- 
You received this message because you are subscribed to the Google Groups 
"Racket Users" group.
To unsubscribe from this group and stop receiving emails from it, send an email 
to racket-users+unsubscr...@googlegroups.com.
For more options, visit https://groups.google.com/d/optout.


Re: [racket-users] Web server hits "Sorry, this page has expired. Please go back."

2018-10-14 Thread Philip McGrath
On Sun, Oct 14, 2018 at 5:30 AM George Neuner  wrote:

> You are absolutely correct that in typical usage globals are not closed
> over ... normally they are considered mutable shared "communication"
> state.
>
> However, I was speaking more generally:  to be persisted long duration,
> and be made portable across separate runtime instances, the continuation
> must close over AND deep copy ANY VALUE the current call chain references.
> You don't (necessarily) want to restart the continuation a week later, on a
> different machine, with different values than when it started.
>

I am definitely not an expert on continuations or PL generally, so I could
be very wrong. My understanding, though, has been that continuations not
closing over non-local variables is a property of continuations in general:
not only in a web context, and not only of the serializable continuations
from `#lang web-server`. (I used those in my example just because it is
easy to see what values they do in fact close over.)

I remember reading in an old mailing list thread (
https://groups.google.com/d/topic/racket-users/mHiVPuYPNiE/discussion), not
in the context of web programming:

On Sep 5, 2012, at 5:39 PM, Harry Spier wrote:

> Is there a way to save any  valid continuation and be guaranteed that
> nothing that happens in the program between the time the continuation was
> saved and the time the saved continuation was invoked will alter the
> results of invoking the continuation.
>
On Wednesday, September 5, 2012 at 5:52:31 PM UTC-4, Matthias Felleisen
wrote:
>
> No. A continuation represents the __control state__ of a program NOT the
> __memory state__.  Since your program can change the memory state while the
> continuation is stored, and since the continuation may reference the memory
> state once it is thrown, there is no way to guarantee the exact same
> outcome in general.
>
> People have experimented with call-with-current-store so that they can
> capture the store and re-install it, especially for continuation launches.
> The SML/NSJ debugger worked like this but in general it is not practical.
>

I definitely understand how it could be useful to have something that did
close over and deep copy any value the current call chain references! But
my understanding (which, again, could be flawed) is that continuations
don't do that.


> I am fully aware of the issues with code mobility in distributed systems.
> Serialized, persisted continuations have all of the same issues - issues
> which mostly are hand-waved and ignored for the sake of efficiency: it's a
> lot easier to tell the programmer that "X won't work" than to go through
> the effort to make it work.  IBM actually tried hard to make a fully
> transactional operating system called "Quicksilver" ... it never left the
> experimental stage.
>
> …  But #lang web-server purports to be able to invoke the saved
> continuation on a different program instance than the one that created it.
>

The documentation for `#lang web-server` does emphatically warn that

> the store is *not* serialized. If you rely on the store you will be
> taking huge risks. You will be assuming that the serialized continuation is
> invoked on the same server before the server is restarted or the memory is
> garbage collected.
>

Additionally, `#lang web-server` protects against some possible errors by
arranging for serialized continuations to no longer be valid if you change
your code:

> the defunctionalization process is sensitive to the syntactic structure of
> your program. Therefore, if you change your program in a trivial way, for
> example, changing a constant, then all serialized continuations will be
> obsolete and will error when deserialization is attempted. This is a
> feature, not an error! It is a small price to pay for protection from the
> sorts of errors that would occur if your program were changed in a
> meaningful way. If you use the default-stuffer
> 
> or web-server/stuffers/hash
> ,
> then whenever you change your servlet’s code, you can safely delete all
> saved continuations, because they won’t be used any longer.
>

As far as I can see, serialized continuations from `#lang web-server`, for
better or for worse, have the same issues in these respects as the kinds of
manually RESTful web applications you might write in various languages with
names beginning in P, where you would marshal an ad-hoc representation of
the continuation into a query parameter, path segment, or hidden form
field. In that case, also, multiple server instances with different
server-side state could create chaos. If you are relying on that kind of
server-side state, though, your web application isn't really RESTful at
all. The web-server language doesn't prevent you from 

Re: [racket-users] Web server hits "Sorry, this page has expired. Please go back."

2018-10-14 Thread George Neuner


On 10/13/2018 9:43 PM, Philip McGrath wrote:
On Sat, Oct 13, 2018 at 6:32 PM George Neuner > wrote:


Remember that a continuation is not a simple thing - in order to
resume a program from a particular point, the entire state of the
current call chain must be preserved: the globals, the call stack,
the thread state, etc. ad nauseam.  If you start to consider
things like JIT'd code, shared memory, message queues, open files,
network connections, etc., the list of what needs to be preserved
is, in theory at least, unbounded.


This isn't quite right: continuations close over the values of local 
(i.e. lexical) variables, control flow/the call stack, and 
continuation marks (most prominently, parameters in the sense of 
`parameterize`), but they do not save global or module-level variables 
or the store in general.


You are absolutely correct that in typical usage globals are not closed 
over ... normally they are considered mutable shared "communication" state.


However, I was speaking more generally:  to be persisted long duration, 
and be made portable across separate runtime instances, the continuation 
must close over AND deep copy ANY VALUE the current call chain 
references.  You don't (necessarily) want to restart the continuation a 
week later, on a different machine, with different values than when it 
started.


I am fully aware of the issues with code mobility in distributed 
systems.  Serialized, persisted continuations have all of the same 
issues - issues which mostly are hand-waved and ignored for the sake of 
efficiency: it's a lot easier to tell the programmer that "X won't work" 
than to go through the effort to make it work.  IBM actually tried hard 
to make a fully transactional operating system called "Quicksilver" ... 
it never left the experimental stage.



Though I have no part in the Racket implementation, I have studied 
compilers and language support fairly extensively.  Language 
implementation was one of my Master tracks in college.  [I went a 
different way for dissertation, but I have all the courses for the 
language oriented degree.]  I've written compilers and runtimes for 
various languages including Scheme-like languages having continuations.



As an illustration, this program prints the serialized form of one of 
`#lang web-server`'s continuations. You can see that the serialized 
representation includes `'lexical-value` but not `'global-value`.


#lang web-server

(require racket/serialize)

(define global
  'global-value)

(call-with-web-prompt
 (λ ()
   (let ([lexical 'lexical-value])
(call-with-serializable-current-continuation
  (λ (k)
    (println (serialize k
 lexical)))


Which is fine in the context of a single running program instance. But 
#lang web-server purports to be able to invoke the saved continuation on 
a different program instance than the one that created it.





But now imagine that 10 different threads have entered that same
call chain and reached that same continuation point.  Now 10
separate instances of the call stacks - and everything they
reference - have to be preserved to support the continuations.


On the same note, I think this depends on what you mean by 
"reference". If each continuation closes over a reference to the same 
shared data structure, the shared value shouldn't be copied. On the 
other hand, if they construct 10 equivalent values (`equal?` but not 
`eq?`), then yes, all 10 will be retained, just as if you'd stored 
them in a mutable hash table without continuations involved.


I'm not trying to play mind games.  Each thread has constructed its own 
unique stack state and they are all existing simultaneously. Whether 
they share references to heap objects is irrelevant for the simple 
continuation scenario ... that becomes important again for the 
*serialized* continuation scenario.




Heavy use of "long-lived" [for some definition of "long"]
continuations in a program can eat up huge amounts of memory.


Despite what I just said, I know that stateful servlets do use a lot 
of memory to retain native continuations in memory: the "Automatically 
RESTful Web Applications" paper says that stateless servlets use ≤10% 
of the memory of stateful equivalents.


By ignoring code mobility issues.  The semantics are kept (relatively) 
simple at the expense of programmer surprise.



I think this is what you're saying, but, to be totally clear, with 
stateless `#lang web-server` servlets, all server-side state is freed 
once the response is sent to the client. (Of course, you can still 
mutate global state, write to files or databases, etc. by stepping 
outside of the continuation system, but you don't need to do any of 
those things.)


I would amend that to "can be freed", and note that I was talking 
specifically about user session state - not program state per se. Web 
continuations are session state as well as program state.



Re: [racket-users] Web server hits "Sorry, this page has expired. Please go back."

2018-10-13 Thread Philip McGrath
On Sat, Oct 13, 2018 at 6:32 PM George Neuner  wrote:

> Remember that a continuation is not a simple thing - in order to resume a
> program from a particular point, the entire state of the current call chain
> must be preserved: the globals, the call stack, the thread state, etc. ad
> nauseam.  If you start to consider things like JIT'd code, shared memory,
> message queues, open files, network connections, etc., the list of what
> needs to be preserved is, in theory at least, unbounded.
>

This isn't quite right: continuations close over the values of local (i.e.
lexical) variables, control flow/the call stack, and continuation marks
(most prominently, parameters in the sense of `parameterize`), but they do
not save global or module-level variables or the store in general.

As an illustration, this program prints the serialized form of one of
`#lang web-server`'s continuations. You can see that the serialized
representation includes `'lexical-value` but not `'global-value`.

#lang web-server

(require racket/serialize)

(define global
  'global-value)

(call-with-web-prompt
 (λ ()
   (let ([lexical 'lexical-value])
 (call-with-serializable-current-continuation
  (λ (k)
(println (serialize k
 lexical)))

But now imagine that 10 different threads have entered that same call chain
> and reached that same continuation point.  Now 10 separate instances of the
> call stacks - and everything they reference - have to be preserved to
> support the continuations.
>

On the same note, I think this depends on what you mean by "reference". If
each continuation closes over a reference to the same shared data
structure, the shared value shouldn't be copied. On the other hand, if they
construct 10 equivalent values (`equal?` but not `eq?`), then yes, all 10
will be retained, just as if you'd stored them in a mutable hash table
without continuations involved.


> Heavy use of "long-lived" [for some definition of "long"] continuations in
> a program can eat up huge amounts of memory.
>

Despite what I just said, I know that stateful servlets do use a lot of
memory to retain native continuations in memory: the "Automatically RESTful
Web Applications" paper says that stateless servlets use ≤10% of the memory
of stateful equivalents.


> Web continuations are kin to general (call/cc) continuations.
>

The stateful web primitives are implemented using `call/cc` and native
continuations. The stateless versions use
`call-with-serializable-current-continuation` and the serializable
representation of continuations from `#lang web-server`.


> So in the scenario above, the state of threads that are [arbitrarily long]
> waiting on user actions might be GC'd to free up memory.
>

 I think this is what you're saying, but, to be totally clear, with
stateless `#lang web-server` servlets, all server-side state is freed once
the response is sent to the client. (Of course, you can still mutate global
state, write to files or databases, etc. by stepping outside of the
continuation system, but you don't need to do any of those things.)

-Philip

-- 
You received this message because you are subscribed to the Google Groups 
"Racket Users" group.
To unsubscribe from this group and stop receiving emails from it, send an email 
to racket-users+unsubscr...@googlegroups.com.
For more options, visit https://groups.google.com/d/optout.


Re: [racket-users] Web server hits "Sorry, this page has expired. Please go back."

2018-10-13 Thread George Neuner

Hi Marc,

On 10/13/2018 3:37 PM, Marc Kaufmann wrote:

Hi George,

thanks, this is incredibly helpful.

On Sat, Oct 13, 2018 at 9:11 PM George Neuner > wrote:


:

3) results from the initial search are written into a dedicated
table in the database.  The Racket program uses the same
continuation scheme and reads out pages of results on demand as in
(2).  Now, since each database query is self contained, and the
user session does not require a persistent DB connection, a larger
number of users can be serviced with a small(er) pool of
connections.  As in (2), all the result data is transitory in the
Racket program, so all that needs to be remembered are the
continuations.

4) results are written into a dedicated table as in (3).  The
Racket program does NOT use continuations, but rather provides a
dedicated result fetch function - separate from the search
function - and generates page URLs which call that function with
appropriate arguments.  Now, in addition to every DBMS query being
self contained, the functions of the Racket application also are
self contained - there is no persistent session state in the
Racket program.


OK, this does give one nice usecase where the distinction is clear. In 
step 4, how should I think of the dedicated fetch function? Say I type 
"continuations web servers racket" in the search, I get 3 pages, and 
the dedicated table has three pages of 10 results each. Then the 
search spits back the first page, as well as a function created on the 
fly that, if provided with argument `page equal to 2 spits out the 
second page, and if equal to 3 spits out the third? And the reason 
this takes less space than a continuation for each page is what? I 
guess it only needs to know the table location and page number, so if 
there are 10 or 100 pages of results, the function still takes the 
same amount of space, while I have 10 or 100 continuations. Is that 
the difference with scenario 3)?


Yes.

Remember that a continuation is not a simple thing - in order to resume 
a program from a particular point, the entire state of the current call 
chain must be preserved: the globals, the call stack, the thread state, 
etc. ad nauseam.  If you start to consider things like JIT'd code, 
shared memory, message queues, open files, network connections, etc., 
the list of what needs to be preserved is, in theory at least, unbounded.


Imagine that at the point where the continuation is created, the program 
is many levels deep in nested function calls, and many KB of data are on 
the stack or referenced by it.  10 continuations taken at that same 
location AND IN that same call chain won't add much because most of the 
state is shared among them (only the resume location might be 
different).  In the stateful program, each continuation descriptor would 
be just a small structure containing a handful of pointers to objects in 
memory.


But now imagine that 10 different threads have entered that same call 
chain and reached that same continuation point.  Now 10 separate 
instances of the call stacks - and everything they reference - have to 
be preserved to support the continuations.


Heavy use of "long-lived" [for some definition of "long"] continuations 
in a program can eat up huge amounts of memory.  The type of 
continuation involved doesn't really matter - you can get into trouble 
using just upward "escape" continuations (let/ec) as readily as you can 
using general continuations (call/cc).  Obviously you can "escape" with 
a general continuation, but the typical usage of let/ec differs 
substantially from the typical use of call/cc.]



Web continuations are kin to general (call/cc) continuations. Compiling 
with the web-server language performs a number of transformations on the 
program which make it possible to serialize continuation state and 
save/restore it as needed.  So in the scenario above, the state of 
threads that are [arbitrarily long] waiting on user actions might be 
GC'd to free up memory.



George

--
You received this message because you are subscribed to the Google Groups "Racket 
Users" group.
To unsubscribe from this group and stop receiving emails from it, send an email 
to racket-users+unsubscr...@googlegroups.com.
For more options, visit https://groups.google.com/d/optout.


Re: [racket-users] Web server hits "Sorry, this page has expired. Please go back."

2018-10-13 Thread Philip McGrath
On Sat, Oct 13, 2018 at 4:02 PM Marc Kaufmann 
wrote:

> If I understand correctly, the stateful servlet stores the continuation in
> the RAM directly (probably in a form that is not that different from the
> serialized one, but slightly more efficiently?), while the stateless
> servlet writes serialized versions to the disk - which also somewhat limits
> what can get stored in a continuation, since not everything is
> serializeable.
>

This is correct, with the caveat that the representation of a serializable
continuation is actually very different from a "native" continuation (i.e.
what you get with `call/cc` in `#lang racket`). You don't actually need to
know these details, but native continuations are a primitive datatype
provided by the runtime system, essentially like closures. The `#lang
web-server` compiler re-writes your module into continuation-passing style,
so that every continuation is explicit. Then it replaces the continuation
lambdas with serializable structs. In principle, you can think of it as
turning a program like this:
> (define ((make-adder x) y)
(+ x y))
> ((make-adder 2) 40)
42
into:
> (serializable-struct adder (x)
#:property prop:procedure
(λ (this y)
  (+ (adder-x this) y)))
> ((adder 2) 40)
42

This is where the restriction on what can be stored in a serialized
continuation comes from: the contents of the closure turn into fields of a
struct, so you can only close over serializable values. On the other hand,
it's fine to work with non-serializable data: you just can't store it in
the continuation across interactions. (In fact, I sometimes intentionally
make structs non-serializable when I want to make sure I don't retain them
across interactions.)

So only the servlet.rkt (where I start the server) should be in `#lang
> web-server`? That sounds fine.
>

I think you may have gotten that backwards: the module(s) where you
*implement* the servlet—e.g. anywhere you use `send/suspend`—need to be in
`#lang web-server`. The module where you actually start the server (with
`serve/servlet` or equivalent), nor do any libraries you use. To be
concrete, here's an example:

#lang racket

(module servlet web-server/lang
  ;; equivalent to #lang web-server
  (provide start)
  (define (start req)
(let loop ([n 0])
  (send/suspend
   (lambda (k-url)
 (response/xexpr
  `(html (head (title "Example Servlet"))
 (body
  (h1 ,(number->string n))
  (p (a ([href ,k-url])
"Add 1")))
  (loop (add1 n)

(module* main racket
  (require web-server/servlet-env
   (submod ".." servlet))
  (serve/servlet start #:stateless? #t))

There is a more specific way to define "the module(s) where you implement
the servlet" to take into account the other requirement of `#lang
web-server`, which is that you can only capture continuations inside
"transformed contexts". There is a simple example in the docs
,
and lots of discussion in the papers, but I basically recommend that you
ignore this until you get an error message. I found it extremely confusing
when I was getting started, and it sent me down the wrong path in debugging
several times, but it has never actually been a problem for me.

Personally, I had experience with RESTful web programming before I came to
>> Racket, and I also started using stateless servlets first. Once it finally
>> clicked, stateless servlets/serializable continuations made sense to me,
>> and I could see that what `#lang web-server` does automatically is really
>> just what I had previously been doing manually and painfully: stuffing all
>> of the data needed to continue the interaction into URL query parameters,
>> hidden form fields, etc.
>>
>
> This! I used to do this all the time and still sometimes do, but recently
> replaced it by continuations. (Thanks to Matthew Butterick's write-up on
> continuations btw, which made them click for me.) However, I ended up with
> n parameters: one for period, one for id, one for phase of the moon, ...
> Every time I changed the code or realized I needed one more state variable,
> I had to refactor all the instances, until it occurred to me to define a
> `struct my-struct and pass that around and then the only place I have to
> change it is in the struct when adding new variables. I know, this should
> have been obvious, but while trying to figure out how to get the
> continuation working, I didn't consciously grasp that all I was doing was
> passing state around, the same way that big-bang in HTDP/2e does it. That
> was a real missing-the-forest-for-the-trees moment for me.
>

I wish I knew how to write something that would reproduce the epiphany
moment I had with this for others. Even after I'd come to Racket, I found
the web server stuff strange and foreign at first and started out using
`net/cgi`, because I already knew how CGI 

Re: [racket-users] Web server hits "Sorry, this page has expired. Please go back."

2018-10-13 Thread Philip McGrath
On Sat, Oct 13, 2018 at 3:11 PM George Neuner  wrote:

> The web-server language helps in conserving memory because its
> continuations can be serialized - stored in files, or in databases, etc. -
> and so the program's continuation state(s) can be persisted to disk rather
> than memory as in a stateful #lang racket program.  For that ability, the
> program necessarily becomes a bit more more complicated (stuffers, etc.).
>

I would be interested to hear in what way you have found stateless `#lang
web-server` servlets more complicated than stateful ones. That hasn't been
my experience, though, as I said, I've used stateless servlets much more
extensively than stateful ones.

In particular, I haven't found stuffers a source of complexity at all. The
only time when I've really had to fiddle with the stuffer at all is when
there are security considerations and I need to guard against forged urls,
but the process for doing that is easy and documented (
http://docs.racket-lang.org/web-server/stateless.html#(def._((lib._web-server%2Fstuffers%2Fhmac-sha1..rkt)._.H.M.A.C-.S.H.A1-stuffer))).
In particular, the security consideration is fundamentally the same as for
any RESTful web program: in fact, I would argue that customizing the
stuffer is easier than trying to check against forged query parameters if
writing an equivalent program manually. Still, there is probably room for
improvement. Maybe `make-default-stuffer` could take an optional keyword
argument to make it sign continuations with a given key?

1) The Racket program can read out all the results [freeing up the DB
> connection], send the 1st page of 20 and include continuation links for the
> additional pages.  But there are 59 pages of results, plus  and
>  where applicable.  Even limiting to, say 10 page links at a time
> [like Google], that means 11 or 12 outstanding continuations kept open on
> this one user session.  AND, no good way to decide when to expire them ...
> the user may go off and examine some result(s) for a while, then come back
> to the list.
>

If I understand your example correctly, stateless servlets essentially let
you write your program like #1 and transforms it into something more like
#4 automatically, as long as your representation of search results is
serializable. The data and context for all of the other page links are
serialized as part of the continuation. If small enough, they are all sent
over to the client; otherwise, their saved in hash-addressed storage and
the client gets the hash to find them again. By default the hash-addressed
storage just uses the filesystem, but you could easily adjust the suffer to
use a database instead.

Of course there are still design considerations, and stateless servlets
don't eliminate those any more than manually RESTful web programming does.
In particular, if the search results might change due to external events
(e.g. the library purchases a new book), you have to decide what to do
about that.


> And cookies can be used to store user session state rather than encoding
> it into URLs (continuation based or not).
>

Just a word of caution here that cookies may or may not be the right notion
of state for a given application: sometimes you really want the semantics
of "web cells" (see "Interaction-Safe State for the Web",
http://scheme2006.cs.uchicago.edu/03-mccarthy.pdf and "Implementation and
Use of the PLT Scheme Web Server",
http://cs.brown.edu/~sk/Publications/Papers/Published/khmgpf-impl-use-plt-web-server-journal/paper.pdf).
I will say that it took me several readings of these papers to get my head
around the ideas well enough to use them, but there I still run into
commercial web applications that use the wrong kind of state.

-Philip

-- 
You received this message because you are subscribed to the Google Groups 
"Racket Users" group.
To unsubscribe from this group and stop receiving emails from it, send an email 
to racket-users+unsubscr...@googlegroups.com.
For more options, visit https://groups.google.com/d/optout.


Re: [racket-users] Web server hits "Sorry, this page has expired. Please go back."

2018-10-13 Thread Marc Kaufmann
On Sat, Oct 13, 2018 at 8:45 PM Philip McGrath 
wrote:

> "Stateless servlets avoid this issue by making continuations serializable,
>> so they can be saved on the client, in a database, etc."
>> Does this mean I have to deal with managing them myself?
>>
>
> No, `#lang web-server` will manage the continuations for you, just as
> stateful servlets do. There is a hook to configure exactly how
> continuations are serialized by providing your own "stuffer," but you don't
> need that to get started. (You should look at the security considerations
> before you go live, but those are easy to deal with if they are relevant to
> your application.)
>
>
Deal with security later has been my mantra since the start...

I did skim the page on stateless servers, but I don't understand who the
>> web server should provide interface-version, stuffer, and start to. Do I
>> have to require this file in all the *.rkt files that uses
>> send/suspend/dispatch?
>>
>
> I had forgotten how confusing I had found the web server documentation
> when I first encountered it. You don't actually need to provide any of
> those things: that part of the documentation, as I understand it, is
> referring to the old (i.e. before my time) way of running servlets before
> `serve/servlet`, `dispatch/servlet`, etc. existed.
>
>
That's good to know. Which reminds me: for future readers (including
probably myself) who are confused by what `serializeable` means, here's
Wikipedia:

"*serialization* is the process of translating data structures
 or object
 state into a
format that can be stored (for example, in a file
 or memory buffer
) or transmitted (for example,
across a network 
connection link) and reconstructed later (possibly in a different computer
environment)."

If I understand correctly, the stateful servlet stores the continuation in
the RAM directly (probably in a form that is not that different from the
serialized one, but slightly more efficiently?), while the stateless
servlet writes serialized versions to the disk - which also somewhat limits
what can get stored in a continuation, since not everything is
serializeable.

As a practical matter, you can start to go stateless just by substituting
>> #lang web-server  for  #lang racket ... odds are that most/all of your
>> program will remain the same.  The web-server language enables you to do
>> things beyond what a stateful Racket server can do, but you don't need to
>> worry about cells and stuffers, etc. until / unless you really need them.
>>
>
> To be a little more specific, `#lang web-server` does two things:
>
>1. It performs a transformation on modules written in `#lang
>web-server` to make continuations within those modules serializable. (It
>also makes anonymous functions serializable.)
>2. It provides alternative versions of web interaction primitives like
>`send/suspend` that work with serializable continuations instead of the
>stateful infrastructure.
>
> #2 means that, in addition to using `#lang web-server`, you need to remove
> `(require web-server/servlet)`, lest the stateful primitives shadow the
> stateless ones.
>
> #1 does *not* mean that you need to use `#lang web-server` for all of
> your modules: in particular, the module in which you call `serve/servlet`
> or `dispatch/servlet` does not necessarily need to be in  `#lang
> web-server`.
>
>
So only the servlet.rkt (where I start the server) should be in `#lang
web-server`? That sounds fine.

In addition, you need to provide a non-false `#:stateless?` argument to
> `serve/servlet` or `dispatch/servlet` to make it set up the context for a
> stateless servlet instead of a stateful one.
>
>
Thanks, this almost surely saved me 15-120 minutes of headscratching.

I have a mixture of both (for no good reason that I couldn't figure out how
>> to do some parts with continuations after starting with them, due to
>> wanting to learn how to use them), but realized that if I hit an error and
>> have to restart the server, all existing users are going to see 'Page
>> expired' links, which isn't Very Good (TM) even by my standards - or
>> especially, since I usually do hit bugs that I have to fix after going live.
>>
>
> Stateless servlets address this problem: serialized continuations remain
> valid across server restarts, multiple servers running behind a load
> balancer, etc. There is a mechanism that renders serialized continuations
> invalid if the relevant source code changes, which is a good thing: the
> potential bugs otherwise would be nightmarish.
>
>
Another problem solved, and together with George's explanation I finally
see what the difference is between the stateful and stateless server.

Is there somewhere a good write-up on a comparison of what is nice 

Re: [racket-users] Web server hits "Sorry, this page has expired. Please go back."

2018-10-13 Thread Marc Kaufmann
Hi George,

thanks, this is incredibly helpful.

On Sat, Oct 13, 2018 at 9:11 PM George Neuner  wrote:

> Hi Marc,
>
> On 10/13/2018 12:17 PM, Marc Kaufmann wrote:
>
>
> On Sat, Oct 13, 2018 at 5:49 PM George Neuner 
> wrote:
>
>>
>> When the program is operating normally, are you seeing *different*
>> continuation URLs every time you execute the same send/suspend/... call?
>> Or are all the URLs for the same send/suspend/... call identical?   IIRC,
>> the default URL generator includes a nonce, but you can create your own
>> URLs.
>>
>>
> The urls have different numbers at the end of the form (("k" . "(6 1
> 8431734)")) if that's what you mean by nonce.
>
>
> Yes.  A "nonce" is (supposed to be) a single use, never repeated, stamp.
> Obviously the "never repeated" part is impractical with reasonably sized
> numbers (rollover), but the point is to generate a unique value that won't
> be repeated within the expected lifetime of the continuation.
>
>
> I generally use stateful servers myself, because I don't use web
>> continuations.  It's not that I don't like them - it's that I don't often
>> have a need for them that isn't better served by using a database.  I
>> certainly do use continuations in my programming - I just don't use web
>> continuations.  I do think that long duration web continuations are a
>> questionable design ... there are just too many error possibilities in the
>> web environment.  Short-lived continuations?  Up to a few minutes?  Maybe
>> ... but I'd need a good use case to justify them.
>>
>
> To clarify, when you say you use a database you mean when the form gets
> posted, there is some variable in the database (say 'page_number') that
> gets incremented, then after the storing in the database, you check the
> database for the page and see the variable is one larger and you post the
> next page? Whereas with continuations there is nothing in the database that
> I can see and the new page is the continuation, as in (generate-page (+ n
> 1))?
>
>
> Not exactly, although that is a valid use case.  The more concurrent
> users, the more it makes sense to use a database to hold session state.
>
>
> My canon example is a database search engine [my own application area].
> User submits search criteria, and [like Google,etc.] gets back a list of
> results.  But say the user wants the results (no more than) 20 per page and
> there are 1172 results.  Now there are some choices about how to structure
> the ongoing session with the user.
>
> 1) The Racket program can read out all the results [freeing up the DB
> connection], send the 1st page of 20 and include continuation links for the
> additional pages.  But there are 59 pages of results, plus  and
>  where applicable.  Even limiting to, say 10 page links at a time
> [like Google], that means 11 or 12 outstanding continuations kept open on
> this one user session.  AND, no good way to decide when to expire them ...
> the user may go off and examine some result(s) for a while, then come back
> to the list.
>
> Keep in mind that (presumably) there will be some number of concurrent
> users doing similar things.
>
> 2) The Racket program can hold a cursor open on the DB results, use the
> same continuation scheme as above, and read out just a page full of results
> on demand when the user wants them.  This approach has the same
> continuations open, and adds a persistent DB connection, but it shifts the
> load of caching results to the DBMS ... result data passing through the
> Racket program now is transitory and can be GC'd if memory is needed.
>
> 3) results from the initial search are written into a dedicated table in
> the database.  The Racket program uses the same continuation scheme and
> reads out pages of results on demand as in (2).  Now, since each database
> query is self contained, and the user session does not require a persistent
> DB connection, a larger number of users can be serviced with a small(er)
> pool of connections.  As in (2), all the result data is transitory in the
> Racket program, so all that needs to be remembered are the continuations.
>
> 4) results are written into a dedicated table as in (3).  The Racket
> program does NOT use continuations, but rather provides a dedicated result
> fetch function - separate from the search function - and generates page
> URLs which call that function with appropriate arguments.  Now, in addition
> to every DBMS query being self contained, the functions of the Racket
> application also are self contained - there is no persistent session state
> in the Racket program.
>
>
OK, this does give one nice usecase where the distinction is clear. In step
4, how should I think of the dedicated fetch function? Say I type
"continuations web servers racket" in the search, I get 3 pages, and the
dedicated table has three pages of 10 results each. Then the search spits
back the first page, as well as a function created on the fly that, if
provided with argument `page equal to 2 spits out the 

Re: [racket-users] Web server hits "Sorry, this page has expired. Please go back."

2018-10-13 Thread George Neuner

Hi Marc,

On 10/13/2018 12:17 PM, Marc Kaufmann wrote:


On Sat, Oct 13, 2018 at 5:49 PM George Neuner > wrote:



When the program is operating normally, are you seeing *different*
continuation URLs every time you execute the same send/suspend/...
call?  Or are all the URLs for the same send/suspend/... call
identical?   IIRC, the default URL generator includes a nonce, but
you can create your own URLs.


The urls have different numbers at the end of the form (("k" . "(6 1 
8431734)")) if that's what you mean by nonce.


Yes.  A "nonce" is (supposed to be) a single use, never repeated, 
stamp.  Obviously the "never repeated" part is impractical with 
reasonably sized numbers (rollover), but the point is to generate a 
unique value that won't be repeated within the expected lifetime of the 
continuation.




I generally use stateful servers myself, because I don't use web
continuations.  It's not that I don't like them - it's that I
don't often have a need for them that isn't better served by using
a database.  I certainly do use continuations in my programming -
I just don't use web continuations.  I do think that long duration
web continuations are a questionable design ... there are just too
many error possibilities in the web environment.  Short-lived
continuations?  Up to a few minutes?  Maybe ... but I'd need a
good use case to justify them.


To clarify, when you say you use a database you mean when the form 
gets posted, there is some variable in the database (say 
'page_number') that gets incremented, then after the storing in the 
database, you check the database for the page and see the variable is 
one larger and you post the next page? Whereas with continuations 
there is nothing in the database that I can see and the new page is 
the continuation, as in (generate-page (+ n 1))?


Not exactly, although that is a valid use case.  The more concurrent 
users, the more it makes sense to use a database to hold session state.



My canon example is a database search engine [my own application area].  
User submits search criteria, and [like Google,etc.] gets back a list of 
results.  But say the user wants the results (no more than) 20 per page 
and there are 1172 results.  Now there are some choices about how to 
structure the ongoing session with the user.


1) The Racket program can read out all the results [freeing up the DB 
connection], send the 1st page of 20 and include continuation links for 
the additional pages.  But there are 59 pages of results, plus  
and  where applicable.  Even limiting to, say 10 page links at 
a time [like Google], that means 11 or 12 outstanding continuations kept 
open on this one user session.  AND, no good way to decide when to 
expire them ... the user may go off and examine some result(s) for a 
while, then come back to the list.


Keep in mind that (presumably) there will be some number of concurrent 
users doing similar things.


2) The Racket program can hold a cursor open on the DB results, use the 
same continuation scheme as above, and read out just a page full of 
results on demand when the user wants them.  This approach has the same 
continuations open, and adds a persistent DB connection, but it shifts 
the load of caching results to the DBMS ... result data passing through 
the Racket program now is transitory and can be GC'd if memory is needed.


3) results from the initial search are written into a dedicated table in 
the database.  The Racket program uses the same continuation scheme and 
reads out pages of results on demand as in (2).  Now, since each 
database query is self contained, and the user session does not require 
a persistent DB connection, a larger number of users can be serviced 
with a small(er) pool of connections.  As in (2), all the result data is 
transitory in the Racket program, so all that needs to be remembered are 
the continuations.


4) results are written into a dedicated table as in (3).  The Racket 
program does NOT use continuations, but rather provides a dedicated 
result fetch function - separate from the search function - and 
generates page URLs which call that function with appropriate 
arguments.  Now, in addition to every DBMS query being self contained, 
the functions of the Racket application also are self contained - there 
is no persistent session state in the Racket program.



Obviously, there has to be some way to expire cached results (easily 
accomplished with a  timestamp that can be updated / extended 
if the user keeps accessing the result set).  And cookies can be used to 
store user session state rather than encoding it into URLs (continuation 
based or not).


The object of the exercise really is to minimize the RAM required 
per-user to maintain state on the server, so that you can serve more 
users with the same amount of resources.  Comparatively, disk space for 
yet-another table (or file) essentially is 

Re: [racket-users] Web server hits "Sorry, this page has expired. Please go back."

2018-10-13 Thread Philip McGrath
>
> "Stateless servlets avoid this issue by making continuations serializable,
> so they can be saved on the client, in a database, etc."
> Does this mean I have to deal with managing them myself?
>

No, `#lang web-server` will manage the continuations for you, just as
stateful servlets do. There is a hook to configure exactly how
continuations are serialized by providing your own "stuffer," but you don't
need that to get started. (You should look at the security considerations
before you go live, but those are easy to deal with if they are relevant to
your application.)

I did skim the page on stateless servers, but I don't understand who the
> web server should provide interface-version, stuffer, and start to. Do I
> have to require this file in all the *.rkt files that uses
> send/suspend/dispatch?
>

I had forgotten how confusing I had found the web server documentation when
I first encountered it. You don't actually need to provide any of those
things: that part of the documentation, as I understand it, is referring to
the old (i.e. before my time) way of running servlets before
`serve/servlet`, `dispatch/servlet`, etc. existed.

As a practical matter, you can start to go stateless just by substituting
> #lang web-server  for  #lang racket ... odds are that most/all of your
> program will remain the same.  The web-server language enables you to do
> things beyond what a stateful Racket server can do, but you don't need to
> worry about cells and stuffers, etc. until / unless you really need them.
>

To be a little more specific, `#lang web-server` does two things:

   1. It performs a transformation on modules written in `#lang web-server`
   to make continuations within those modules serializable. (It also makes
   anonymous functions serializable.)
   2. It provides alternative versions of web interaction primitives like
   `send/suspend` that work with serializable continuations instead of the
   stateful infrastructure.

#2 means that, in addition to using `#lang web-server`, you need to remove
`(require web-server/servlet)`, lest the stateful primitives shadow the
stateless ones.

#1 does *not* mean that you need to use `#lang web-server` for all of your
modules: in particular, the module in which you call `serve/servlet` or
`dispatch/servlet` does not necessarily need to be in  `#lang web-server`.

In addition, you need to provide a non-false `#:stateless?` argument to
`serve/servlet` or `dispatch/servlet` to make it set up the context for a
stateless servlet instead of a stateful one.

I have a mixture of both (for no good reason that I couldn't figure out how
> to do some parts with continuations after starting with them, due to
> wanting to learn how to use them), but realized that if I hit an error and
> have to restart the server, all existing users are going to see 'Page
> expired' links, which isn't Very Good (TM) even by my standards - or
> especially, since I usually do hit bugs that I have to fix after going live.
>

Stateless servlets address this problem: serialized continuations remain
valid across server restarts, multiple servers running behind a load
balancer, etc. There is a mechanism that renders serialized continuations
invalid if the relevant source code changes, which is a good thing: the
potential bugs otherwise would be nightmarish.

Is there somewhere a good write-up on a comparison of what is nice about
> one style vs the other? I am not asking which is better, but examples that
> highlight how they are different or lead to different solutions or
> different trade-offs?
>

There is a gap in the documentation, I think. (Maybe I should try to write
some more.) I know that I did find reading Jay's papers helpful, even if
the formal PL parts were over my head:

   - "Automatically RESTful Web Applications: Marking Modular Serializable
   Continuations": https://doi.org/10.1145/1596550.1596594
   - "The Two-State Solution: Native and Serializable Continuations
   Accord":
   https://jeapostrophe.github.io/home/static/oopsla026-mccarthy.pdf

Personally, I had experience with RESTful web programming before I came to
Racket, and I also started using stateless servlets first. Once it finally
clicked, stateless servlets/serializable continuations made sense to me,
and I could see that what `#lang web-server` does automatically is really
just what I had previously been doing manually and painfully: stuffing all
of the data needed to continue the interaction into URL query parameters,
hidden form fields, etc. The benefits of stateless servlets are mostly just
the benefits of not using server-side state in general. The main
disadvantage is that you need to ensure data structures that will be
serialized as part of the closure are serializable. However, while it takes
some practice to get a sense of this (maybe another opportunity for more
documentation), it isn't actually a big problem in practice.

-Philip

On Sat, Oct 13, 2018 at 12:18 PM Marc Kaufmann 
wrote:

>
> On Sat, Oct 13, 

Re: [racket-users] Web server hits "Sorry, this page has expired. Please go back."

2018-10-13 Thread Marc Kaufmann
On Sat, Oct 13, 2018 at 5:49 PM George Neuner  wrote:

> Hi Marc,
>
> On 10/13/2018 10:42 AM, Marc Kaufmann wrote:
>
> Thanks George and Philip.
>
> George, while I am sure that in some places I allow using continuations
> after a delay, that's not what I meant. What I feel is happening (with
> little evidence, mind you) is that, when I come back to my website after 3
> days and open the homepage, it creates it on the fly with a *new*
> continuation (generated now), yet when the link gets called it gives me
> this error. I would have thought this continuation is new, yet it seems to
> throw the error I am talking about more often when I haven't visited the
> site in a while. See below for the servlet I am using currently, I am not
> specifying a manager.
>
>
> Which means you are using the default manager. That would explain an old
> continuation expiring, but not a new one.
>
> When the program is operating normally, are you seeing *different*
> continuation URLs every time you execute the same send/suspend/... call?
> Or are all the URLs for the same send/suspend/... call identical?   IIRC,
> the default URL generator includes a nonce, but you can create your own
> URLs.
>
>
The urls have different numbers at the end of the form (("k" . "(6 1
8431734)")) if that's what you mean by nonce.

>
> Philip, thanks, I didn't realize that I had made an active choice. I am
> pretty sure I was simply using stateful servlets because the
> send/suspend/dispatch link on "Continue: Web Applications in Racket" links
> to the stateful servlets page, not to the stateless servlets page. If this
> is not best practice, maybe it would be better to link it to the
> send/suspend/dispatch on the stateless server page. You say:
>
> "Stateless servlets avoid this issue by making continuations serializable,
> so they can be saved on the client, in a database, etc."
>
> Does this mean I have to deal with managing them myself?
>
> Practically speaking, since both of you seem to imply that I should use
> stateless servers, how do I do that? I did skim the page on stateless
> servers, but I don't understand who the web server should provide
> interface-version, stuffer, and start to. Do I have to require this file in
> all the *.rkt files that uses send/suspend/dispatch?
>
>
> It's not really a matter of "best practice" ... stateful vs stateless
> mostly is a non-issue unless you have limited memory or you really need web
> continuations to be available long duration: e.g., hours or days.
>
> I generally use stateful servers myself, because I don't use web
> continuations.  It's not that I don't like them - it's that I don't often
> have a need for them that isn't better served by using a database.  I
> certainly do use continuations in my programming - I just don't use web
> continuations.  I do think that long duration web continuations are a
> questionable design ... there are just too many error possibilities in the
> web environment.  Short-lived continuations?  Up to a few minutes?  Maybe
> ... but I'd need a good use case to justify them.
>
>
To clarify, when you say you use a database you mean when the form gets
posted, there is some variable in the database (say 'page_number') that
gets incremented, then after the storing in the database, you check the
database for the page and see the variable is one larger and you post the
next page? Whereas with continuations there is nothing in the database that
I can see and the new page is the continuation, as in (generate-page (+ n
1))?

I have a mixture of both (for no good reason that I couldn't figure out how
to do some parts with continuations after starting with them, due to
wanting to learn how to use them), but realized that if I hit an error and
have to restart the server, all existing users are going to see 'Page
expired' links, which isn't Very Good (TM) even by my standards - or
especially, since I usually do hit bugs that I have to fix after going live.

Is there somewhere a good write-up on a comparison of what is nice about
one style vs the other? I am not asking which is better, but examples that
highlight how they are different or lead to different solutions or
different trade-offs?


> As a practical matter, you can start to go stateless just by substituting
> #lang web-server  for  #lang racket ... odds are that most/all of your
> program will remain the same.  The web-server language enables you to do
> things beyond what a stateful Racket server can do, but you don't need to
> worry about cells and stuffers, etc. until / unless you really need them.
>
>
I'll try that and see what happens. Thanks a lot!

> George
>

Marc

-- 
You received this message because you are subscribed to the Google Groups 
"Racket Users" group.
To unsubscribe from this group and stop receiving emails from it, send an email 
to racket-users+unsubscr...@googlegroups.com.
For more options, visit https://groups.google.com/d/optout.


Re: [racket-users] Web server hits "Sorry, this page has expired. Please go back."

2018-10-13 Thread George Neuner

Hi Marc,

On 10/13/2018 10:42 AM, Marc Kaufmann wrote:

Thanks George and Philip.

George, while I am sure that in some places I allow using 
continuations after a delay, that's not what I meant. What I feel is 
happening (with little evidence, mind you) is that, when I come back 
to my website after 3 days and open the homepage, it creates it on the 
fly with a *new* continuation (generated now), yet when the link gets 
called it gives me this error. I would have thought this continuation 
is new, yet it seems to throw the error I am talking about more often 
when I haven't visited the site in a while. See below for the servlet 
I am using currently, I am not specifying a manager.


Which means you are using the default manager. That would explain an old 
continuation expiring, but not a new one.


When the program is operating normally, are you seeing *different* 
continuation URLs every time you execute the same send/suspend/... 
call?  Or are all the URLs for the same send/suspend/... call 
identical?   IIRC, the default URL generator includes a nonce, but you 
can create your own URLs.



Philip, thanks, I didn't realize that I had made an active choice. I 
am pretty sure I was simply using stateful servlets because the 
send/suspend/dispatch link on "Continue: Web Applications in Racket" 
links to the stateful servlets page, not to the stateless servlets 
page. If this is not best practice, maybe it would be better to link 
it to the send/suspend/dispatch on the stateless server page. You say:


"Stateless servlets avoid this issue by making continuations 
serializable, so they can be saved on the client, in a database, etc."


Does this mean I have to deal with managing them myself?

Practically speaking, since both of you seem to imply that I should 
use stateless servers, how do I do that? I did skim the page on 
stateless servers, but I don't understand who the web server should 
provide interface-version, stuffer, and start to. Do I have to require 
this file in all the *.rkt files that uses send/suspend/dispatch?


It's not really a matter of "best practice" ... stateful vs stateless 
mostly is a non-issue unless you have limited memory or you really need 
web continuations to be available long duration: e.g., hours or days.


I generally use stateful servers myself, because I don't use web 
continuations.  It's not that I don't like them - it's that I don't 
often have a need for them that isn't better served by using a 
database.  I certainly do use continuations in my programming - I just 
don't use web continuations.  I do think that long duration web 
continuations are a questionable design ... there are just too many 
error possibilities in the web environment.  Short-lived continuations?  
Up to a few minutes?  Maybe ... but I'd need a good use case to justify 
them.



As a practical matter, you can start to go stateless just by 
substituting  #lang web-server  for  #lang racket ... odds are that 
most/all of your program will remain the same.  The web-server language 
enables you to do things beyond what a stateful Racket server can do, 
but you don't need to worry about cells and stuffers, etc. until / 
unless you really need them.


George

--
You received this message because you are subscribed to the Google Groups "Racket 
Users" group.
To unsubscribe from this group and stop receiving emails from it, send an email 
to racket-users+unsubscr...@googlegroups.com.
For more options, visit https://groups.google.com/d/optout.


Re: [racket-users] Web server hits "Sorry, this page has expired. Please go back."

2018-10-13 Thread Marc Kaufmann
Thanks George and Philip.

George, while I am sure that in some places I allow using continuations
after a delay, that's not what I meant. What I feel is happening (with
little evidence, mind you) is that, when I come back to my website after 3
days and open the homepage, it creates it on the fly with a *new*
continuation (generated now), yet when the link gets called it gives me
this error. I would have thought this continuation is new, yet it seems to
throw the error I am talking about more often when I haven't visited the
site in a while. See below for the servlet I am using currently, I am not
specifying a manager.

Philip, thanks, I didn't realize that I had made an active choice. I am
pretty sure I was simply using stateful servlets because the
send/suspend/dispatch link on "Continue: Web Applications in Racket" links
to the stateful servlets page, not to the stateless servlets page. If this
is not best practice, maybe it would be better to link it to the
send/suspend/dispatch on the stateless server page. You say:

"Stateless servlets avoid this issue by making continuations serializable,
so they can be saved on the client, in a database, etc."

Does this mean I have to deal with managing them myself?

Practically speaking, since both of you seem to imply that I should use
stateless servers, how do I do that? I did skim the page on stateless
servers, but I don't understand who the web server should provide
interface-version, stuffer, and start to. Do I have to require this file in
all the *.rkt files that uses send/suspend/dispatch?

#lang

 web-server 
(require

 web-server/http)
(provide

 interface-version

 stuffer

 start

)
(define

 interface-version

 'stateless)
(define

 stuffer

  (stuffer-chain

   serialize-stuffer

   (md5-stuffer

 (build-path

 (find-system-path

 'home-dir) ".urls"
(define

 (start

 req)
  (response/xexpr

   `(html (body (h2 "Look ma, no state!")

Right now, the following is my servlet.rkt file that I start via racket
servlet.rkt:

#lang racket

(require web-server/servlet
 web-server/servlet-env
 db
 racket/date
 web-server/configuration/responders
 web-server/formlets
 "pages.rkt"
 )

;;; Much ado about nothing
...

(serve/servlet start
   #:log-file (build-path (string-append "logs/" date-string
"server.logs"))
   #:servlet-path "/"
   #:servlet-regexp #rx""
   #:launch-browser? #f
   #:extra-files-paths (list (build-path "htdocs"))
   #:servlet-responder my-error-responder)

Thanks 

Re: [racket-users] Web server hits "Sorry, this page has expired. Please go back."

2018-10-13 Thread George Neuner


On 10/13/2018 9:27 AM, Marc Kaufmann wrote:

Hi all,

I am running the Racket web server with continuations and I keep 
getting "Sorry, this page has expired. Please go back." rather 
sporadically. I can't seem to figure out why and when this happens. I 
get it more on my local server running on localhost.


A few patterns that I believe are true (without having rigorously 
tested it):


- When I don't visit my live server for a while (and hence noone 
does), I usually get the error immediately and then when I go back and 
try again it works. Is it possible that it is an issue of something 
(the continuation URL) not being loaded quickly or having to be 
generated on the fly? Would a database connection that has expired 
lead to this? I remember having issues with my database connections 
going stale (or whatever I'm supposed to call that).
- When I refresh a page, I often get it too (although sometimes that 
fixes the problem?)


This is not a crippling issue, but my guess is that I am doing 
something wrong in how I set up things and eventually I should deal 
with this.


Cheers,
Marc


I would question a design that allows invoking continuations after very 
long delays.  It certainly is possible, e.g., using a stateless server 
(#lang web-server), or by saving state in your database ... but I still 
wouldn't do it.  E.g., I have a search engine app that caches results 
for a time in an unlogged database table, but I don't use web 
continuations to page through them: the initial search specifies the 
requested result "page" size, and a separate retrieval URL requires the 
search id and page #.


AFAIK, a closed DB connection won't cause the error you see ... it will 
do other bad things .  You can use virtual connections [if your 
SQL doesn't rely on prepared statements] to get around the problem, or 
[as I do] use some variety of (with-db-connection ...) macro to get a 
new (pool?) connection whenever you need it.



Did you use  serve-servlet  to start your server running?  If so, did 
you specify a particular continuation manager in the call?  The default 
manager will time out cached continuations after ~4 hours.


see:

   
https://docs.racket-lang.org/web-server/run.html?q=serve-servlet#%28def._%28%28lib._web-server%2Fservlet-env..rkt%29._serve%2Fservlet%29%29
   
https://docs.racket-lang.org/web-server/servlet.html?q=serve-servlet#%28def._%28%28lib._web-server%2Fmanagers%2Flru..rkt%29._make-threshold-.L.R.U-manager%29%29


George

--
You received this message because you are subscribed to the Google Groups "Racket 
Users" group.
To unsubscribe from this group and stop receiving emails from it, send an email 
to racket-users+unsubscr...@googlegroups.com.
For more options, visit https://groups.google.com/d/optout.


[racket-users] Web server hits "Sorry, this page has expired. Please go back."

2018-10-13 Thread Marc Kaufmann
Hi all,

I am running the Racket web server with continuations and I keep getting 
"Sorry, this page has expired. Please go back." rather sporadically. I 
can't seem to figure out why and when this happens. I get it more on my 
local server running on localhost.

A few patterns that I believe are true (without having rigorously tested 
it):

- When I don't visit my live server for a while (and hence noone does), I 
usually get the error immediately and then when I go back and try again it 
works. Is it possible that it is an issue of something (the continuation 
URL) not being loaded quickly or having to be generated on the fly? Would a 
database connection that has expired lead to this? I remember having issues 
with my database connections going stale (or whatever I'm supposed to call 
that).
- When I refresh a page, I often get it too (although sometimes that fixes 
the problem?)

This is not a crippling issue, but my guess is that I am doing something 
wrong in how I set up things and eventually I should deal with this.

Cheers,
Marc

-- 
You received this message because you are subscribed to the Google Groups 
"Racket Users" group.
To unsubscribe from this group and stop receiving emails from it, send an email 
to racket-users+unsubscr...@googlegroups.com.
For more options, visit https://groups.google.com/d/optout.