[racket] web server: module servlets

閲覧: 44 回
最初の未読メッセージにスキップ

George Neuner

未読、
2014/09/23 16:45:022014/09/23
To: us...@racket-lang.org
Hi,

I'm using 6.0.1 and I have a couple of questions regarding module
servlets. I'm new to the server side of Racket so please be gentle.


1) Is there any way to speed up initial servlet loading? Even for a
very simple servlet (does nothing, canned response for testing)
several seconds elapse before it responds to the browser. I tried
compiling it to bytecode with raco, but having the ./compiled/.zo file
available doesn't seem to make any noticeable difference. I know the
bytecode still is JIT'd before execution, but I thought eliminating
the source compile step would have helped more.

Does a web server require the .zo file to be in a different location
than ./compiled? Or does it not deal with bytecode files at all?


2) Debugging module servlets is a pain due to having to stop/restart
the server. Is there some clever way to force the server to unload a
particular servlet but keep running?

I thought about starting the listener in a thread, but I can't figure
how to get at either the thread or the custodian from within a
servlet. Would listener termination have to be done from a hardcoded
function at the top level?


Apologies if these questions are stupid.

Thanks,
George

____________________
Racket Users list:
http://lists.racket-lang.org/users

Jay McCarthy

未読、
2014/09/23 18:09:582014/09/23
To: George Neuner、users
On Tue, Sep 23, 2014 at 4:42 PM, George Neuner <gneu...@comcast.net> wrote:
> Hi,
>
> I'm using 6.0.1 and I have a couple of questions regarding module
> servlets. I'm new to the server side of Racket so please be gentle.
>
>
> 1) Is there any way to speed up initial servlet loading? Even for a
> very simple servlet (does nothing, canned response for testing)
> several seconds elapse before it responds to the browser. I tried
> compiling it to bytecode with raco, but having the ./compiled/.zo file
> available doesn't seem to make any noticeable difference. I know the
> bytecode still is JIT'd before execution, but I thought eliminating
> the source compile step would have helped more.
>
> Does a web server require the .zo file to be in a different location
> than ./compiled? Or does it not deal with bytecode files at all?
>

This is why I recommend that new users use serve/servlet, which is
much faster because it does not use namespaces or live loading.

> 2) Debugging module servlets is a pain due to having to stop/restart
> the server. Is there some clever way to force the server to unload a
> particular servlet but keep running?
>
> I thought about starting the listener in a thread, but I can't figure
> how to get at either the thread or the custodian from within a
> servlet. Would listener termination have to be done from a hardcoded
> function at the top level?

Doing this pretty much requires not following my advice in question 1,
but the default server (used by the command line tool) allows you to
go to "/conf/refresh-servlets" and unload/reload all the servlet code.

The way that you would know that is by following the link from the
command-line docs

http://docs.racket-lang.org/web-server/run.html#%28part._command-line-tools%29

to the web-server@ unit which is the implementation of the dispatch
sequence the command-line tool uses:

http://docs.racket-lang.org/web-server-internal/Web_Servers.html#%28def._%28%28lib._web-server%2Fweb-server-unit..rkt%29._web-server~40%29%29

>
> Apologies if these questions are stupid.
>
> Thanks,
> George
>
> ____________________
> Racket Users list:
> http://lists.racket-lang.org/users



--
Jay McCarthy
http://jeapostrophe.github.io

"Wherefore, be not weary in well-doing,
for ye are laying the foundation of a great work.
And out of small things proceedeth that which is great."
- D&C 64:33

George Neuner

未読、
2014/09/23 21:23:442014/09/23
To: Jay McCarthy、users
Hi Jay,


On 9/23/2014 6:04 PM, Jay McCarthy wrote:
On Tue, Sep 23, 2014 at 4:42 PM, George Neuner <gneu...@comcast.net>
 wrote:
>
> 1) Is there any way to speed up initial [module] servlet loading?

This is why I recommend that new users use serve/servlet, which is
much faster because it does not use namespaces or live loading.

That's an option for a finished application ... if a web application ever really can
be said to be finished ... but it's tough when you're developing. 

I guess the question is "where is all the time spent"?  Loading required modules
from the library I suppose?

Not really knowing much about Racket's internals he naively asks: Could a server
pre-load the commonly used webserver modules and make them available
to new module servlets, or does the custodian implementation make doing that
difficult/impossible?

> 2) Debugging module servlets is a pain due to having to stop/restart
> the server.  Is there some clever way to force the server to unload a
> particular servlet but keep running?

Doing this pretty much requires not following my advice in question 1,
but the default server (used by the command line tool) allows you to
go to "/conf/refresh-servlets" and unload/reload all the servlet code.

That might help.  Does unloading & reloading affect a stateless servlet that isn't
been changed?  More to the point, can you stop/restart the server and continue
a stateless servlet?

My application so far is based on stateful servlets and AJAX ... stateful mainly because
it's easier for me to understand.  Currently there is little use of continuations, but
some planned functionality will use them extensively and it certainly would help if
debugging didn't always mean starting over setting up conditions in the application.

George

Jay McCarthy

未読、
2014/09/23 22:07:542014/09/23
To: George Neuner、users
On Tue, Sep 23, 2014 at 9:19 PM, George Neuner <gneu...@comcast.net> wrote:
> Hi Jay,
>
> On 9/23/2014 6:04 PM, Jay McCarthy wrote:
>
> On Tue, Sep 23, 2014 at 4:42 PM, George Neuner <gneu...@comcast.net> wrote:
>>
>> 1) Is there any way to speed up initial [module] servlet loading?
>
> This is why I recommend that new users use serve/servlet, which is
> much faster because it does not use namespaces or live loading.
>
>
> That's an option for a finished application ... if a web application ever
> really can
> be said to be finished ... but it's tough when you're developing.

Hi George,

The command-line tool is basically deprecated and only provided for
backwards compatibility. There is a huge amount that it can't do at
all and it hasn't been the primary way that we recommend using the Web
server for a very long time.

> I guess the question is "where is all the time spent"? Loading required
> modules
> from the library I suppose?

Yes.

> Not really knowing much about Racket's internals he naively asks: Could a
> server
> pre-load the commonly used webserver modules and make them available
> to new module servlets, or does the custodian implementation make doing that
> difficult/impossible?

This is the purpose of the make-servlet-namespace argument of
configuration-table->web-config@ but there is no option in the
configuration file for that argument.

http://docs.racket-lang.org/web-server-internal/Web_Servers.html?q=servlet-namespace#%28def._web-config._%28%28lib._web-server%2Fweb-config-unit..rkt%29._configuration-table-~3eweb-config~40%29%29

>> 2) Debugging module servlets is a pain due to having to stop/restart
>> the server. Is there some clever way to force the server to unload a
>> particular servlet but keep running?
>
> Doing this pretty much requires not following my advice in question 1,
> but the default server (used by the command line tool) allows you to
> go to "/conf/refresh-servlets" and unload/reload all the servlet code.
>
>
> That might help. Does unloading & reloading affect a stateless servlet that
> isn't
> been changed? More to the point, can you stop/restart the server and
> continue
> a stateless servlet?

Yes, that's the goal of stateless servlets :)

> My application so far is based on stateful servlets and AJAX ... stateful
> mainly because
> it's easier for me to understand. Currently there is little use of
> continuations, but
> some planned functionality will use them extensively and it certainly would
> help if
> debugging didn't always mean starting over setting up conditions in the
> application.

This comment/question is related to questions 4 and 5 from the FAQ:

http://docs.racket-lang.org/web-server/faq.html?q=servlet-namespace#%28part._update-servlets%29

George Neuner

未読、
2014/09/25 12:54:052014/09/25
To: Jay McCarthy、users
Hi Jay,


On 9/23/2014 10:03 PM, Jay McCarthy wrote:
The command-line tool is basically deprecated and only provided for
backwards compatibility. There is a huge amount that it can't do at
all and it hasn't been the primary way that we recommend using the Web
server for a very long time.

I'm not using the plt-web-server app - I created a minimal application that set up the environment: directories, ports, etc. and a start function that just returns a 404 if called.  My server sits behind Apache and only handles servlets, which I would like to be demand load modules so they can be added to and updated easily.  That's why I am interested in being able to unload servlets on command, though not necessarily all of them at once (although that also is helpful).



> Not really knowing much about Racket's internals he naively asks: 
> Could a server  pre-load the commonly used webserver modules and make
> them available to new module servlets, or does the custodian 
> implementation make doing that difficult/impossible?

This is the purpose of the make-servlet-namespace argument of
configuration-table->web-config@ but there is no option in the
configuration file for that argument.

http://docs.racket-lang.org/web-server-internal/Web_Servers.html?q=servlet-namespace#%28def._web-config._%28%28lib._web-server%2Fweb-config-unit..rkt%29._configuration-table-~3eweb-config~40%29%29

The namespace facility seems designed more for user written modules than for library modules. 

My analysis may be off-base as I have very little experience working directly with custodians, but it seems that when a dynamic servlet is first loaded, its custodian spends a lot of additional time (re)loading library modules that already exist in other custodians.  [ Though I can't tell exactly what's happening, I can see a lot of disk activity when I think I'm loading a 5KB servlet. ]  Reasonably I would have expected that after loading/linking the first servlet, the libraries common to the servlets would be already in memory.  But loading additional servlets is no quicker [ and causes a similar disk hit ] so clearly I don't understand what is happening internally with the custodians.

If a Racket library is deliberately put into the servlet-namespace, does that streamline linking?



> My application so far is based on stateful servlets and AJAX ... stateful
> mainly because it's easier for me to understand.  Currently there is 
> little use of continuations, but some planned functionality will use them
> extensively and it certainly would help if debugging didn't always mean
> starting over setting up conditions in the application.

This comment/question is related to questions 4 and 5 from the FAQ:

http://docs.racket-lang.org/web-server/faq.html?q=servlet-namespace#%28part._update-servlets%29

That link leads to a "troubleshooting" page 8-).  I didn't consider the issue to be a "problem" per se - I already knew that restarting a stateful servlet would lose saved state.  Most of my existing servlets are one-shots that don't save any state, but they are written using the stateful language.  Only a few use continuations and not extensively (so far).  I was just thinking ahead to stuff that will need to use continuations more extensively.

Thanks for putting up with my questions.
George

Jay McCarthy

未読、
2014/09/25 13:06:342014/09/25
To: George Neuner、users
Your assumption about the purpose of this is not correct. Anything in
the servlet-namespace will be shared between all servlets, and thus
not loaded per-servlet.

>> My application so far is based on stateful servlets and AJAX ... stateful
>> mainly because it's easier for me to understand. Currently there is
>> little use of continuations, but some planned functionality will use them
>> extensively and it certainly would help if debugging didn't always mean
>> starting over setting up conditions in the application.
>
> This comment/question is related to questions 4 and 5 from the FAQ:
>
> http://docs.racket-lang.org/web-server/faq.html?q=servlet-namespace#%28part._update-servlets%29
>
>
> That link leads to a "troubleshooting" page 8-). I didn't consider the
> issue to be a "problem" per se - I already knew that restarting a stateful
> servlet would lose saved state. Most of my existing servlets are one-shots
> that don't save any state, but they are written using the stateful language.
> Only a few use continuations and not extensively (so far). I was just
> thinking ahead to stuff that will need to use continuations more
> extensively.
>
> Thanks for putting up with my questions.
> George
>



George Neuner

未読、
2014/09/25 16:35:482014/09/25
To: Jay McCarthy、users
Hi Jay,


On 9/25/2014 1:04 PM, Jay McCarthy wrote:
> If a Racket library is deliberately put into the servlet-namespace, does
> that streamline linking?

Your assumption about the purpose of this is not correct. Anything in
the servlet-namespace will be shared between all servlets, and thus
not loaded per-servlet.

I think you misunderstood my question, but you may have answered it anyway.

What I really was asking was whether each custodian was having to individually load common Racket libraries [ web-server/*, net/*, etc. ] for a new servlet rather than all servlet custodians sharing libraries that are already loaded.  Or, if not actually "loading" the libraries, then having to go to disk to check dependencies.

So if I create a shared servlet namespace and put, e.g., "web-server/servlet" into it, would that in any way speed up starting a new dynamically loaded servlet?

George

Jay McCarthy

未読、
2014/09/25 18:28:582014/09/25
To: George Neuner、users
There is a very small set that is automatically shared:
racket/base
web-server/private/servlet
web-server/http
web-server/servlet/web
...

web-server/servlet is NOT shared, nor is any net library or common
racket library like racket/list. They are all totally unique per
servlet.

This, by the way, is part of why I don't recommend using dynamic
servlets at all and suggest using serve/servlet.

Jay

George Neuner

未読、
2014/09/26 0:20:422014/09/26
To: Jay McCarthy、users
On 9/25/2014 6:26 PM, Jay McCarthy wrote:
web-server/servlet is NOT shared, nor is any net library or common
racket library like racket/list. They are all totally unique per
servlet.

This, by the way, is part of why I don't recommend using dynamic
servlets at all and suggest using serve/servlet.

But ... IIUC ... a listener started by  serve/servlet  will still dynamically load from <servlet-root>, <server-root>/htdocs/*, etc. if the request doesn't match a hard coded dispatch URL - the regex of the initial servlet or an entry in a dispatcher table.  At least that's the behavior I see with my own application: my initial servlet returns 404 when called - the call to  serve/servlet  just sets up the environment and and all the "real" servlets are demand loaded from disk when first touched.

Are you advocating *static* linking and essentially just dispatching to internal functions by URL?  ISTM that that defeats the purpose.

George

Jay McCarthy

未読、
2014/09/26 20:09:512014/09/26
To: George Neuner、users
Hi George,

I suggest that all Racket web-server apps not use the dynamic features
of serve/servlet either, but instead write the servlet as the single
"request -> response" function that serve/servlet provides. This would
ensure that all the libraries are loaded the one time and has the best
performance out of all the options of the Web server. Furthermore,
there are many features (such as total URL control) that are only
available in this model.

In case it is not completely clear, here's a little example (<500
lines) of a Web application that works this way:

https://github.com/plt/racket/blob/master/pkgs/plt-services/meta/pkg-index/official/dynamic.rkt#L423

Here's another that uses 'serve' directly for non-servlet needs:

https://github.com/jeapostrophe/exp/blob/master/dir-serve.rkt

And here's a considerably longer one:

https://github.com/jeapostrophe/grade-samurai/blob/master/app.rkt#L2020

I highly recommend using serve/servlet like this over any other
options. In particular, many of the problems you're talking about were
the reason that I made serve/servlet in the first place.

Jay

George Neuner

未読、
2014/11/20 0:47:552014/11/20
To: users
Hi all,

Using 6.0.1

I was under the (maybe mistaken) impression that calling response/...
terminated the servlet thread. It seems though that it doesn't. I was
hoping to use response as an early exit, so that my servlets look like:
e.g.,

(define (user/exists request)
(let* [
(params (request-bindings request))
(username (exists-binding? 'username params))
(response (make-hash))
]

; validate request
(unless username
(response/json (hasheq 'success #f 'msg "missing username" ))

; get request parameters
(set! username (extract-binding/single 'username params))

:

; send a real response
(response/json response )
))


(define (response/json obj . cookies )
(response/output
(λ (op) (write-json obj op))
#:code 200
#:message #"OK"
#:seconds (current-seconds)
#:mime-type #"application/javascript"
#:headers (map cookie->header cookies)
))

I expected that unless would bail out if the test fails. However,
execution charges ahead into code that extracts post parameters and/or
cookie values and then I get a contract error that terminates the
servlet ... usually before my own error response is sent.

Is response supposed to terminate the servlet? If not, can I wrap a
let/ec around the whole servlet and do something like:

(define (user/exists request)
(let/ec fail
(let* [
(params (request-bindings request))
(username (exists-binding? 'username params))
(response (make-hash))
]

; validate request
(unless username
(response/json (hasheq 'success #f 'msg "missing username" )
(fail))

; get request parameters
(set! username (extract-binding/single 'username params))

:

; send a real response
(response/json response )
)))

or do I have to arrange that the response always is the last value produced?

Thanks,
George

Jay McCarthy

未読、
2014/11/20 9:41:182014/11/20
To: George Neuner、users
A response is a value. The various response/* functions just return
these values. A servlet is a "request -> response" function, which
means that the response you send back is the value the servlet
returns. Your use of an escape continuation to simulate C's "return"
statement is standard practice. However, the Web server offers an
effect function called 'send/back' with the type "response -> doesn't"
that will accept a response and send it back to the user, never
returning to the code that called it. I suspect you will find it nicer
to use this if you know the function isn't returning the response to a
DIFFERENT function that post-processes the response.

Jay

--
Jay McCarthy
http://jeapostrophe.github.io

"Wherefore, be not weary in well-doing,
for ye are laying the foundation of a great work.
And out of small things proceedeth that which is great."
- D&C 64:33

____________________

George Neuner

未読、
2014/11/21 1:40:072014/11/21
To: Jay McCarthy、users
Hi Jay,

On 11/20/2014 9:39 AM, Jay McCarthy wrote:
> A response is a value. The various response/* functions just return
> these values. A servlet is a "request -> response" function, which
> means that the response you send back is the value the servlet
> returns.

I think that's where I got the idea that the response/... functions
terminated the servlet. There are a few examples in which response/...
is the final function called in the servlet, but there aren't any
examples that show sending a response from the middle except for those
invoking the send/... functions. But those examples also involve saving
continuations so I associated send/... with continuation saving.

> Your use of an escape continuation to simulate C's "return"
> statement is standard practice. However, the Web server offers an
> effect function called 'send/back' with the type "response -> doesn't"
> that will accept a response and send it back to the user, never
> returning to the code that called it. I suspect you will find it nicer
> to use this if you know the function isn't returning the response to a
> DIFFERENT function that post-processes the response.

Thanks, that look's like what I want. The idea here is that the input
is invalid so the servlet can't continue.

> Jay
全員に返信
投稿者に返信
転送
新着メール 0 件