You are viewing an old version of this page. View the current version.

Compare with Current View Page History

« Previous Version 7 Next »

Actor API중 Become/Unbecome으로 간단한 상태변환 액터 설계가가능하지만

조금더 복잡한 상태머신이 필요할시 AbstatractFSM 객체 활용이 가능합니다.


상태머신 디자인샘플


언랭에서의 유한상태머신 디자인 컨셉에서 영향을 받았습니다.

http://erlang.org/documentation/doc-4.8.2/doc/design_principles/fsm.html


배치잡 상태머신설계

배치 처리기를 다음과 같이 설계한다고 가정해봅시다.

  • 메시지를 일정량 모아뒀다가 내가 원하는 타이밍에 모아서 처리하고 싶다.
  • 특정시간이 지나면, 모은량과 상관없이 자동으로 처리하고 싶다.


메시지가 불규칙적으로 생산된다고 가정하고, 메시지발생시마다 매번 DBwrite를 수행한다고 하면

DB의 성능저하를 일으키는 요소가될것입니다. 

1초란 시간은 네트워크에서 아주긴 시간입니다. 초당 100메시지 전송이 가능하다고 하면

어떠한 처리 함수를 100번호출하는것보다. 1번호출로 100개의데이터를 묶어서 처리하는것이 대부분 유용합니다.


배치 상태설계를 정의하면 다음과 같습니다.

  • 상태값은 대기와 활동상태 두개를 가진다.
  • 특정 시간이 지나면 활동상태로 깨어난다.
  • 메시지는 항상 큐에 적재가 되며 활동상태일때 처리를 합니다.
  • 필요하면 임의로 큐를 비워서 배치처리가 되도록합니다.


구현-기반구조체정의

import akka.actor.AbstractFSM;
import akka.actor.ActorRef;
import akka.japi.pf.UnitMatch;
import java.util.Arrays;
import java.util.LinkedList;
import java.util.List;
import java.io.Serializable;
import java.time.Duration;


public final class SetTarget  {
  private final ActorRef ref;

  public SetTarget(ActorRef ref) {
    this.ref = ref;
  }

  public ActorRef getRef() {
    return ref;
  }

  @Override
  public String toString() {
    return "SetTarget{" +
      "ref=" + ref +
      '}';
  }
}


public final class Queue  {
  private final Object obj;

  public Queue(Object obj) {
    this.obj = obj;
  }

  public Object getObj() {
    return obj;
  }

  @Override
  public String toString() {
    return "Queue{" +
      "obj=" + obj +
      '}';
  }
}


public final class Batch {
  private final List<Object> list;

  public Batch(List<Object> list) {
    this.list = list;
  }

  public List<Object> getList() {
    return list;
  }

  @Override
  public boolean equals(Object o) {
    if (this == o) return true;
    if (o == null || getClass() != o.getClass()) return false;

    Batch batch = (Batch) o;

    return list.equals(batch.list);
  }

  @Override
  public int hashCode() {
    return list.hashCode();
  }

  @Override
  public String toString() {
    final StringBuilder builder = new StringBuilder();
    builder.append( "Batch{list=");
    list.stream().forEachOrdered(e -> { builder.append(e); builder.append(","); });
    int len = builder.length();
    builder.replace(len, len, "}");
    return builder.toString();
  }
}


public enum Flush {
  Flush
}


//states
enum State {
Idle, Active
}

//state data
interface Data {
}

enum Uninitialized implements Data {
Uninitialized
}

final class Todo implements Data {
private final ActorRef target;
private final List<Object> queue;

public Todo(ActorRef target, List<Object> queue) {
 this.target = target;
 this.queue = queue;
}

public ActorRef getTarget() {
 return target;
}

public List<Object> getQueue() {
 return queue;
}

@Override
public String toString() {
 return "Todo{" +
   "target=" + target +
   ", queue=" + queue +
   '}';
}

public Todo addElement(Object element) {
 List<Object> nQueue = new LinkedList<>(queue);
 nQueue.add(element);
 return new Todo(this.target, nQueue);
}

public Todo copy(List<Object> queue) {
 return new Todo(this.target, queue);
}

public Todo copy(ActorRef target) {
 return new Todo(target, this.queue);
}
}










  • No labels