3

I want omit all the same type of messages except the last one:

def receive =  {
   case Message(type:MessageType, data:Int) =>
     // remove previous and get only last message of passed MessageType
}

for example when I send:

actor ! Message(MessageType.RUN, 1)
actor ! Message(MessageType.RUN, 2)
actor ! Message(MessageType.FLY, 1)

then I want to recevie only:

Message(MessageType.RUN, 2)
Message(MessageType.FLY, 1)

Of course if they will be send very fast, or on high CPU load

Michał Jurczuk
  • 3,728
  • 4
  • 32
  • 56
  • What if there is also `Message(MessageType.FLY, 2)`? How do you know that the message is last? – om-nom-nom Jul 03 '14 at 17:27
  • This numbers are just an example, there also could be just `String`. I have a lot of messages, and when CPU is slowing down I don't want handle all this messages but only last. Queue is making bigger and bigger, and I want remove all message and get only last – Michał Jurczuk Jul 03 '14 at 17:34
  • I can change messasges to MessageRun and MessageFly, but main the point is to omit messages and get only last – Michał Jurczuk Jul 03 '14 at 17:37
  • [This answer to another question](http://stackoverflow.com/a/7673389/3004881) suggests a way to check the length of messages currently in the mailbox, and simply never process a message when it's not the last one. Maybe there's some way to adapt it to your needs. However, you'd need to be careful to (1) check that it still works in your version of Akka, (2) not drop the last message of any type, and (3) still process something if messages are constantly arriving. – Dan Getz Jul 04 '14 at 11:38

2 Answers2

3

You could wait a very short amount of time, storing the most recent messages that arrive, and then process only those most recent ones. This can be accomplished by sending messages to yourself, and scheduleOnce. See the second example under the Akka HowTo: Common Patterns, Scheduling Periodic Messages. Instead of scheduling ticks whenever the last tick ends, you can wait until new messages arrive. Here's an example of something like that:

case class ProcessThis(msg: Message)
case object ProcessNow

var onHold = Map.empty[MessageType, Message]
var timer: Option[Cancellable] = None

def receive = {
  case msg @ Message(t, _) =>
    onHold += t -> msg
    if (timer.isEmpty) {
      import context.dispatcher
      timer = Some(context.system.scheduler.scheduleOnce(1 millis, self, ProcessNow))
    }
  case ProcessNow =>
    timer foreach { _.cancel() }
    timer = None
    for (m <- onHold.values) self ! ProcessThis(m)
    onHold = Map.empty
  case ProcessThis(Message(t, data)) =>
    // really process the message
}

Incoming Messages are not actually processed right away, but are stored in a Map that keeps only the last of each MessageType. On the ProcessNow tick message, they are really processed.

You can change the length of time you wait (in my example set to 1 millisecond) to strike a balance between responsivity (length of time from a message arriving to response) and efficiency (CPU or other resources used or held up).

Dan Getz
  • 8,774
  • 6
  • 30
  • 64
0

type is not a good name for a field, so let's use messageType instead. This code should do what you want:

var lastMessage: Option[Message] = None

def receive =  {
  case m => {
    if (lastMessage.fold(false)(_.messageType != m.messageType)) {
      // do something with lastMessage.get
    }
    lastMessage = Some(m)
  }
}
wingedsubmariner
  • 13,350
  • 1
  • 27
  • 52
  • This is not what exacly I mean. When I will send only Message(MessageType.RUN, 1) ... Message(MessageType.RUN,100) on high CPU load, I want get last message which has been sent at that time, for example: 10, 22, 34 etc. random but always the latest message in queue. Is it possible to check or remove something from queue messages? – Michał Jurczuk Jul 03 '14 at 17:15