简体   繁体   English

如何使用Snap Framework维护服务器端状态?

[英]How do I maintain a server-side state with Snap Framework?

Server-side sessions are not [yet] part of the Snap Framework. 服务器端会话不是Snap Framework的一部分。 Is there a way to add some sort of server side state? 有没有办法添加某种服务器端状态?

Let's pretend I want to increment a counter for each HTTP request. 让我假装我想为每个HTTP请求增加一个计数器。 How would I do it? 我该怎么办?

The above answer is correct as far as it goes, but it doesn't deal with some real issues. 上述答案是正确的,但它没有涉及一些实际问题。

First up is server restarts. 首先是服务器重启。 If your storage is more than caching, it needs to be durable across server restarts. 如果您的存储不仅仅是缓存,则需要在服务器重新启动时保持持久性。

Second is code reloading. 第二是代码重新加载。 Future versions of Snap, starting with 0.3 (probably due in early December) will have dynamic code reloading in development use. Snap的未来版本,从0.3开始(可能在12月初到期)将在开发使用中重新加载动态代码。 This is a huge advantage in terms of development speed, but it makes server-local state an interesting mental exercise. 这在开发速度方面是一个巨大的优势,但它使服务器本地状态成为一项有趣的心理练习。 If the programmer changes the type/initialization/whatever of the server-local state, it needs to be re-initialized. 如果程序员更改了类型/初始化/服务器本地状态,则需要重新初始化。 There are some tremendous engineering challenges there. 那里有一些巨大的工程挑战。

When I was writing the dynamic-reloading code for 0.3, I struggled with that issue for for a while. 当我编写0.3的动态重载代码时,我在这个问题上挣扎了一段时间。 Then I looked at other platforms. 然后我看了其他平台。 PHP? PHP? Stores everything externally (database, memcache, whatever). 在外部存储所有内容(数据库,内存缓存等)。 No cross-request storage in-memory at all. 根本没有内存中的交叉请求存储。 Ruby on Rails? Ruby on Rails? Same. 相同。

When combined with the challenges inherent in the first issue, I came to the conclusion that the server should be stateless, aside from possible caching optimizations. 结合第一期中固有的挑战,我得出结论,除了可能的缓存优化之外,服务器应该是无状态的。 Leave durability concerns for libraries/external processes that are designed for it. 保留为其设计的库/外部进程的持久性问题。

So I designed the common interface used by the production and development loaders (one uses static loading, the other dynamic loading) to take 3 functions: An initialization function, a cleanup function, and a handler that uses the state returned by the initialization function. 所以我设计了生产和开发加载器使用的通用接口(一个使用静态加载,另一个使用动态加载)来获取3个函数:初始化函数,清理函数和使用初始化函数返回的状态的处理程序。 In production mode, that compiles down to calling initialize at server startup, and cleanup at server shutdown. 在生产模式下,编译为在服务器启动时调用initialize,在服务器关闭时进行清理。 In development mode, it compiles down to: for each request, dynamically load all 3, then run init, handler, cleanup. 在开发模式下,它编译为:对于每个请求,动态加载所有3,然后运行init,handler,cleanup。 Obviously, no state will survive cross-request that way. 显然,任何国家都不会以这种方式交叉请求。

And then my answer becomes: Do your cross-request storage via some mechanism with built-in durability, and have the server state just be the interface to that. 然后我的答案变成:通过一些具有内置持久性的机制进行交叉请求存储,并使服务器状态成为其接口。 Use something like happstack-state or sqlite if you want to work in-process, or a database or some other external store if you want to work outside the local process. 如果要在进程内工作,请使用happstack-state或sqlite之类的东西,如果要在本地进程外工作,请使用数据库或其他外部存储。

Just as an added note, managing "global" resources like a connection pool or the like is also far easier in Snap 0.3, due to the addition of the MonadSnap interface. 同样作为补充说明,由于添加了MonadSnap接口,在Snap 0.3中管理“全局”资源(如连接池等)也变得更加容易。

Easiest way is to put the state behind an mvar: 最简单的方法是将状态置于mvar之后:

fooHandler :: MVar Int -> Snap ()
fooHandler mvar = do
    x <- liftIO $ modifyMVar mvar $ \y -> let y'=y+1 in (y',y')
    writeBS $ S.pack $ "Incremented counter to: " ++ show x

Initialize the mvar when the site is initialized. 初始化站点时初始化mvar。 Hope this helps. 希望这可以帮助。

I found two session-related packages: 我发现了两个与会话相关的包:

snap-auth is made by the the Snap Framework team, or at least by one of its authors/contirbutor (Ozgun Ataman). snap-auth由Snap Framework团队制作,或者至少由其作者/ contirbutor(Ozgun Ataman)制作。 It targets authentication and session management. 它针对身份验证和会话管理。 The session management is done using a map of ByteString to ByteString, implying you can only store data that has already been serialized to a ByteString: 使用ByteString到ByteString的映射完成会话管理,这意味着您只能将已经序列化的数据存储到ByteString:

type Session = Map ByteString ByteString

On the other hand, mysnapsession allows you to use an arbitrary type to model your session. 另一方面, mysnapsession允许您使用任意类型来建模会话。 There is however some helper functions for sessions of the Map type. 但是, Map类型的会话有一些辅助函数。 More details here . 更多细节在这里 The author, Chris Smith, is also part of the Snap Framework project. 作者Chris Smith也是Snap Framework项目的一部分。

声明:本站的技术帖子网页,遵循CC BY-SA 4.0协议,如果您需要转载,请注明本站网址或者原文地址。任何问题请咨询:yoyou2525@163.com.

 
粤ICP备18138465号  © 2020-2024 STACKOOM.COM