在某项目里,有个 actor 需要做一些持久化的操作,这些操作耗时比较久,理应使用异步的代码来写,但是需求又强调每次只能做一个持久化操作,后来的请求应该等待。一个显然的做法是阻塞式的写,这样就能比较简单的实现顺序花操作。

代码写完以后,我觉得在 actor 中 block 不够完美,就想其他的解决方案。实际上,借助 akka actor 的一些函数,可以实现在不阻塞的情况下实现顺序执行请求的功能的。这种办法的核心是使用 become, unbecome 函数:actor 设置两种状态 free 和 busy,当 free 的时,处理消息,当 busy 时,暂时将消息存储起来,处理消息后,给 actor 返回 done 指令,actor 的状态重新返回到 free,准备处理下一个请求。具体的实现又有很多细节可以考虑,比如当 busy 时到来的请求存储到哪里,是 stash 起来还是在 actor 内部维护一个 queue。请求的处理逻辑是写在 actor 内部,还是借鉴 cameo 模式,再创建一个 actor。

网上已有一种实现,我看了下,觉得应该没有问题。只不过 actor 内部维护了一个 queue,这可能会造成 actor 死亡后重启数据丢失的情况。更好的办法应该是 cameo 模式创建新的 actor 来处理可能出现异常(危险)的工作,其次是把 actor 的 mailbox 当做那个 queue,不要自己维护,按照 doc 缩写,actor 重启后,mailbox 的消息不会丢失。

package actors

import scala.concurrent.Future
import scala.concurrent.ExecutionContext.Implicits.global import akka.actor.{ Actor, ActorRef } import play.api.libs.concurrent.Akka
import play.api.Logger
import play.api.Play.current trait SequentialActor {
this: Actor => import SequentialActor._ // Actor defines type Receive as PartialFunction[Any, Unit]
type ReceiveAsync = PartialFunction[Any, Future[_]] private val queue = scala.collection.mutable.Queue[Job]()
private def enqueue(job: Job): Unit = queue enqueue job
private def dequeue: Option[Job] = if (queue.isEmpty) None else Some(queue.dequeue) private var _senderAsync: ActorRef = _
def senderAsync = _senderAsync def receive: Receive = {
case msg =>
context become busy
process(Job(msg, sender))
} def busy: Receive = {
case Done =>
dequeue match {
case None => context.unbecome
case Some(job) => process(job)
}
case msg =>
enqueue(Job(msg, sender))
} def process(job: Job) {
_senderAsync = job.sender
(receiveAsync orElse fallback)(job.msg).onComplete { _ => self ! Done }
} def receiveAsync: ReceiveAsync def fallback: ReceiveAsync = {
case msg =>
Logger.error(s"Unhandled message: $msg")
Future.successful{ () }
} }
object SequentialActor {
case object Done
case class Job(msg: Any, sender: ActorRef)
}

  

顺序执行到来的消息 actor的更多相关文章

  1. 关于MQ的几件小事(五)如何保证消息按顺序执行

    1.为什么要保证顺序 消息队列中的若干消息如果是对同一个数据进行操作,这些操作具有前后的关系,必须要按前后的顺序执行,否则就会造成数据异常.举例: 比如通过mysql binlog进行两个数据库的数据 ...

  2. .NET中按预定顺序执行任务

    更新记录 本文迁移自Panda666原博客,原发布时间:2021年7月1日. 一.说明 在.NET中线程可以定义按先后顺序进行执行,适合部分有先后次序的业务逻辑.Task也可以按照预定义的先后顺序执行 ...

  3. js的并行加载以及顺序执行

    重新温习了下这段内容,发现各个浏览器的兼容性真的是搞大了头,处理起来很是麻烦. 现在现总结下并行加载多个js的方法: 1,对于动态createElement('script')的方式,对所有浏览器都是 ...

  4. 【原创】cs+html+js+css模式(七): 顺序执行与并发执行问题,IIS7及其以上版本的抛错问题解决

          在进行开发的过程中,针对于这种模式,我们继承的IRequiresSessionState,这种对于我们的同一个IIS的执行中是顺序执行即一个ajax请求处理完成后,才能执行下一个ajax, ...

  5. testng xml中按顺序执行java类

    如红字部份,将安顺序执行4个类 <?xml version="1.0" encoding="UTF-8"?><suite name=" ...

  6. js的并行加载与顺序执行

    javaScript文件(下面简称脚本文件)需要被HTML文件引用才能在浏览器中运行.在HTML文件中可以通过不同的方式来引用脚本文件,我们需要关注的是,这些方式的具体实现和这些方式可能会带来的性能问 ...

  7. gulp顺序执行任务

    gulp的任务的执行是异步的. 所以,当我写完一系列的任务,准备一股脑地执行. # gulp.task('prod', ['clean', 'compass', 'image', 'style', ' ...

  8. testng.xml顺序执行多个case配置

    testng.xml顺序执行多个case配置 项目结构如图:

  9. 多命令顺序执行、管道符 ; && || |

    多命令顺序执行:

随机推荐

  1. unity3d asset store下载的代码所在位置

    Asset Store下载了官方的示例,却找不到了,又不想重新下载 PC:C:\Users\PCNAME\AppData\Roaming\Unity\Asset StoreMAC:"~/Li ...

  2. Mac直播服务器Nginx配置对HLS的支持

    在上一篇中Mac上搭建直播服务器Nginx+rtmp,我们已经搭建了nginx+rtmp直播服务器.下面需要对Nginx服务器增加对HLS的支持.在Nginx增加对HLS种支持比较简单,只是简单的修改 ...

  3. 要杀死一切APP,微信应用号是不是被神化了?

    昨晚打开微信朋友圈,关于微信“小程序”发布内测邀请函的消息漫天飞舞.今天一早翻阅新闻,各大媒体也纷纷表示看好微信应用号,有些媒体甚至扬言微信应用号将杀死一切APP,大量的APP都将会被用户卸载.不可否 ...

  4. java继承8个题

    1.实现如下类之间的继承关系,并编写Music类来测试这些类. public class Instrument { public void play(){ System.out.println(&qu ...

  5. JSTL核心标签库使用

    JSTL是什么? java standard taglib(java标准标签库). 标签是什么? sun公司制订的一种技术规范,用来将jsp页面中的java代码使用类似于html当中的标记来替换 的一 ...

  6. 分析Linux内核中进程的调度(时间片轮转)-《Linux内核分析》Week2作业

    1.环境的搭建: 这个可以参考孟宁老师的github:mykernel,这里不再进行赘述.主要是就是下载Linux3.9的代码,然后安装孟宁老师编写的patch,最后进行编译. 2.代码的解读 课上的 ...

  7. MAT(Memory Analyzer Tool)工具入门介绍(转)

    1.MAT是什么? MAT(Memory Analyzer Tool),一个基于Eclipse的内存分析工具,是一个快速.功能丰富的JAVA heap分析工具,它可以帮助我们查找内存泄漏和减少内存消耗 ...

  8. Entity Framework 5.0基础系列

    1.Entity Framework简介 http://www.cnblogs.com/aehyok/p/3315991.html 2.Entity Framework DBFirst尝试http:/ ...

  9. 【VerySky原创】后台JOB运行-相关表

    [VerySky原创] TBTCP    批作业步骤概述TBTCO    作业状态概述表TBTCS    批计划表TBTC_SPOOLID    Background Processing Spool ...

  10. C# 设置和获取一个字节的某一位的值的方法

    自己工作中遇到需要对单字节的高位.低位进行赋值,即一个字节byte,想要给每一位都赋值,这个值是动态来的,是0或是1. 好不容易收集到一些珍贵资料,整理一下: 一.设置 方法code: /// < ...