clojure中三目运算符_Web应用程序剖析:我如何在Clojure中构建RedditLater

clojure中三目运算符

I made RedditLater last year to allow people to post to Reddit at some pre-scheduled time. It has a modest usage; a few hundred visitors per day, with some fraction of those scheduling posts. In this article, I’ll write about how RedditLater works, and why I made some of the decisions I did.

去年,我做了RedditLater ,以便人们可以在预定的时间发布到Reddit。 它用法适中; 每天有数百名访问者,其中一些只是预定的帖子。 在本文中,我将介绍RedditLater的工作原理,以及为什么要做出一些决定。

建筑 (Architecture)

I wrote the project about a year ago. It’s hosted on a single Heroku dyno. I chose Heroku because, hey, free hosting. So technical decisions were made with these limitations in mind – even though usage is modest, the hosting environment is quite limited. The app had to be able to deliver its scheduled posts (approximately) on time, and survive the occasional traffic surge from itself being posted on reddit.

我大约一年前写了这个项目。 它托管在单个Heroku测功机上。 我选择Heroku是因为免费托管。 因此,在制定技术决策时会考虑到这些限制–即使使用量不大,托管环境也相当有限。 该应用必须能够(按时)按时发送预定的帖子,并且能够承受因在reddit上发布而引起的偶尔流量激增的情况。

RedditLater works by spinning up a separate worker thread to monitor the queue of posts destined for Reddit, which runs alongside the web server. The worker thread just goes through the list of queued posts and sends them to reddit whenever it finds one where schedule < now.

RedditLater通过旋转一个单独的工作线程来监视发往Reddit的帖子队列,该帖子与Web服务器一起运行。 worker线程只浏览排队的帖子列表,并在找到schedule < now地方将它们发送到reddit。

RedditLater was written using Clojure. I chose Clojure mostly because I was way into Clojure at the time. I still am, but I was then too. In retrospect, though, I can say it was a fine decision. Clojure is a simple, functional language with top-notch support for concurrency. It’s not exactly mainstream, but it’s popular enough to have first-class support on Heroku. RedditLater relies on the concurrency that Clojure makes so accessible to run parallel tasks on that one Heroku instance, especially the Lamina library and its excellent queue structures.

RedditLater是使用Clojure编写的。 我之所以选择Clojure,主要是因为当时我很喜欢Clojure 。 我仍然是,但那时也是。 回想起来,我可以说这是一个很好的决定。 Clojure是一种简单的功能语言,具有对并发的一流支持。 它并不完全是主流,但是它很流行,足以在Heroku上提供一流的支持 。 RedditLater依赖Clojure如此易于访问的并发性,以在该Heroku实例上运行并行任务,尤其是Lamina库及其出色的队列结构。

For persistence, posts and user login data are stored in a Mongo database hosted on MongoHQ, which plays nicely with Heroku. I used Mongo because the app isn’t database-intensive, and because Mongo is easy to use, especially from a language with a hash-map literal as Clojure has.

为了保持持久性,帖子和用户登录数据存储在MongoHQ上托管的Mongo数据库中,该数据库可与Heroku完美配合。 我之所以使用Mongo,是因为该应用程序不占用数据库资源,并且因为Mongo易于使用,尤其是像Clojure那样具有哈希映射文字的语言。

(I’ve come to think of Mongo as the datastore you use until you need to make a decision about which datastore to use.)

(在考虑到要使用哪个数据存储区之前,我已经将Mongo视为您使用的数据存储区。)

总览 (Overview)

The application requires a few bits of functionality that can be separated into agnostic modules. The main functionality can be divided between the request handler and the worker. The request handler is the UI and frontend of the app, accepting user input. The worker takes care of actually posting things to Reddit.

该应用程序需要一些可分离为不可知模块的功能。 主要功能可以在请求处理程序和工作程序之间划分。 请求处理程序是应用程序的UI和前端,接受用户输入。 工人负责将事情实际发布到Reddit。

请求处理程序 (Request Handler)

Here’s an overview of the tasks the web worker performs in a typical workflow, where a user logs in and schedules a post:

以下是网络工作者在典型的工作流程中执行的任务的概述,其中用户登录并计划发布:

  • Serve a rendered template routed by URL

    提供通过URL路由的渲染模板
  • Authenticate user with Reddit via Reddit’s OAuth support

    通过Reddit的OAuth支持使用Reddit验证用户
  • Store user’s authentication credentials for future Reddit API calls in mongo

    在mongo中存储用户的身份验证凭据以供将来的Reddit API调用
  • Store the desired post (including scheduled time) in mongo

    将所需的帖子(包括计划的时间)存储在mongo中
  • Put the post into the worker’s queue for posting

    将帖子放入工人的队列以进行发布

The request handler is written using the Ring library, the de-facto standard for Clojure web apps, with Compojure handling routing, and Enlive taking care of template rendering. I also used Middleman to mock out the UI and generate HTML templates to be used with enlive.

请求处理程序是使用Ring库编写的, Ring库是Clojure Web应用程序的实际标准, Compojure处理路由,而Enlive负责模板渲染。 我还使用Middleman来模拟UI并生成与enlive一起使用的 HTML模板。

There’s nothing too interesting here, just the Clojure equivalents of some really mundane tasks that any developer could relate to. The more interesting part is the post queue. One bonus aspect of using Clojure is that it’s both easy and performant to start your request-serving machinery from your application. This is because Clojure’s concurrency is thread-based (in-process), while Python, Ruby, PHP etc. use multi-process concurrency.

这里没有什么太有趣的了,只是与任何开发人员可能涉及的一些真正平凡的任务的Clojure等效项。 更有趣的部分是发布队列。 使用Clojure的一个好处是从应用程序启动请求服务机制既简单又高效。 这是因为Clojure的并发是基于线程的(进程内),而Python,Ruby,PHP等使用了多进程并发。

工人 (Worker)

On the worker side, the situation is much simpler:

在工人方面,情况要简单得多:

  • Take a post from the queue.

    从队列中发帖。
  • Fetch the latest version of that post from Mongo.

    从Mongo获取该帖子的最新版本。
  • Check if it’s time to submit this post.

    检查是否该提交该帖子了。

    • If not, put the post at the end of the queue.

      如果不是,请将帖子放在队列的末尾。
    • If so, attempt to post. If the attempt fails, add the post back to the queue.

      如果是这样,请尝试发布。 如果尝试失败,则将帖子添加回队列。
  • Repeat.

    重复。

Here’s an annotated example of how this all looks:

这是这一切的注释示例:

(Syntax primer: myfunction(x, y) in Algol-derived languages is (myfunction x y) in Clojure.)

(语法引物:Algol衍生语言中的myfunction(x, y) (myfunction xy)在Clojure中是(myfunction xy) 。)

;; Define a post queue
(def upcoming-post-queue (lamina/queue))

(defn enqueue-post
  "Enqueue a post in the post queue."
  [post]
  (lamina/enqueue upcoming-post-queue post))

(defn time-to-post?
  "Is schedule < now?"
  [post]
  (>= (get post :schedule) (helpers/now)))

(defn process-post
  "Grab a post from the queue. If it's time to post it, post it. If not, requeue."
  []
  (let [post @upcoming-post-queue] ; Blocks until a post is in the queue
    (if (time-to-post? post)
      (reddit-api/submit post) ; If so, submit the post with the reddit-api module
      (enqueue-post post)))    ; Otherwise, add the post to the queue
  (Thread/sleep 1000.)) ; Sleep for a second


;; Called by main on startup
(defn start-worker []
  (doall (repeatedly process-post)))

If you can get over the parentheses, you can see how this process is simplified when compared to solutions in languages like Python (Celery) or Ruby (Resque). Both of these require you to run and manage another process (for another $30 per month, on Heroku), and neither has quite as simple of an API.

如果您能克服括号,则可以看到与Python( Celery )或Ruby( Resque )等语言的解决方案相比,该过程是如何简化的。 这两个都要求您运行和管理另一个进程(每月在Heroku上要另外花费30美元),而且都没有一个API这么简单。

Of course, there is a downside – scaling this architecture across many servers would require that the post queue implement some sort of sharding. But this method would scale vertically on one server pretty far before it became necessary to distribute processing. After all, since the queue handles locking, there’s no reason but server specs that you couldn’t start as many worker threads as you like.

当然,这有一个缺点-在许多服务器上扩展此体系结构将需要发布队列实现某种分片。 但是,这种方法将在需要分发处理之前在一台服务器上垂直扩展。 毕竟,由于队列可以处理锁定,因此没有理由,但服务器规范无法启动任意数量的辅助线程。

结论 (Conclusion)

And that’s all there is to it! Using only these simple tools, RedditLater has been running happily and continuously for over a year (with the occasional bugfix). Of course, there are many other ways to design such an application, but I hope you’ve learned a bit today from the design and the tools I chose. For more on how Redditlater itself works, here’s some more detail.

这就是全部! 仅使用这些简单的工具,RedditLater便愉快且连续运行了一年多(偶尔有错误修复)。 当然,还有许多其他方法可以设计这样的应用程序,但是我希望您今天从我选择的设计和工具中学到了一些东西。 有关Redditlater本身如何工作的更多信息 ,这里有一些更多细节

翻译自: https://www.sitepoint.com/anatomy-web-app-redditlater-clojure/

clojure中三目运算符

  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值