使用Firebase实时数据库的发布/订阅事件

时间:2016-10-02 17:39:57

标签: firebase firebase-realtime-database publish-subscribe

我正在尝试使用Firebase实时数据库为分布式系统实施pub / sub。我想要像Amazon SQS这样的东西,但我不知道我怎么能保证只有一个用户会处理这个消息。

交易会完成这项工作吗?有没有办法锁定一行或类似的东西?

更新

以下是我目前的订户代码,这样安全吗?

public class TaskToRun {
    private String id;
    private String data;
    private boolean running;
    //getters and setters
}

public class TaskSubscriber implements ChildEventListener{
    private Query reference;
    private LinkedList<TaskToRun> queue = new LinkedList<>();
    private Object lockQueue = new Object();
    private final Semaphore available = new Semaphore(1, true);
    private boolean running;
    public TaskSubscriber(){
        reference = FirebaseDatabase.getInstance().getReference().child("tasks").orderByChild("running").equalTo(false);
    }
    public void start(){
        running = true;
        queue.clear();
        reference.addChildEventListener(this);
        AsyncTask t = new AsyncTask() {
            @Override
            protected Object doInBackground(Object[] objects) {
                while (running){
                    try {
                        available.acquire();
                        if(!running)
                            break;
                        TaskToRun task = null;
                        synchronized(lockQueue){
                            if(queue.size() > 0){
                                task = queue.pop();
                            }
                        }
                        if(task != null){

                            //Try to update the object to running
                            Transaction.Handler handler = new Transaction.Handler() {
                                private boolean canRun = false;
                                @Override
                                public Transaction.Result doTransaction(MutableData mutableData) {
                                    canRun = false;

                                    TaskToRun t = mutableData.getValue(TaskToRun.class);
                                    if(t == null)
                                        return  Transaction.success(mutableData);
                                    if(t.isRunning())
                                        return Transaction.success(mutableData);

                                    t.setRunning(true);
                                    mutableData.setValue(t);
                                    canRun = true;
                                    return  Transaction.success(mutableData);

                                }

                                @Override
                                public void onComplete(DatabaseError databaseError, boolean b, DataSnapshot dataSnapshot) {
                                    if(canRun && databaseError == null) {
                                        runTask(dataSnapshot.getValue(TaskToRun.class));

                                    }
                                }
                            };
                            FirebaseDatabase.getInstance().getReference().child("tasks").child(task.getId()).runTransaction(handler);

                        }
                    } catch (InterruptedException e) {
                        e.printStackTrace();
                    }
                }
                return null;
            }
        };
        t.execute();
    }
    private void runTask(TaskToRun task) {
        Log.e("TASKS","Running task "+task.getId());
        try {
            Thread.sleep(10000);
        } catch (InterruptedException e) {
            e.printStackTrace();
        }
    }
    public void stop(){
        running = false;
        reference.removeEventListener(this);
        synchronized (lockQueue) {
            queue.clear();
        }
        //Release all threads
        int usedPermits = 1 - available.availablePermits();
        available.release(usedPermits);
    }

    @Override
    public void onChildAdded(DataSnapshot dataSnapshot, String s) {
        synchronized (lockQueue){
            TaskToRun task = dataSnapshot.getValue(TaskToRun.class);
            task.setId(dataSnapshot.getKey());
            if(!task.isRunning()){
                queue.addLast(task);
                available.release();
            }
        }
    }

    @Override
    public void onChildChanged(DataSnapshot dataSnapshot, String s) {
        synchronized (lockQueue){
            TaskToRun task = dataSnapshot.getValue(TaskToRun.class);
            task.setId(dataSnapshot.getKey());

            if(task.isRunning()){
                for(int i = 0; i < queue.size();i++){
                    TaskToRun t  = queue.get(i);
                    if(t.getId().equals(task.getId())){
                        queue.remove(i);
                        break;
                    }
                }
            }
        }
    }

    @Override
    public void onChildRemoved(DataSnapshot dataSnapshot) {
        synchronized (lockQueue){
            TaskToRun task = dataSnapshot.getValue(TaskToRun.class);
            task.setId(dataSnapshot.getKey());

            if(task.isRunning()){
                for(int i = 0; i < queue.size();i++){
                    TaskToRun t  = queue.get(i);
                    if(t.getId().equals(task.getId())){
                        queue.remove(i);
                        break;
                    }
                }
            }
        }
    }

    @Override
    public void onChildMoved(DataSnapshot dataSnapshot, String s) {

    }

    @Override
    public void onCancelled(DatabaseError databaseError) {

    }
}

主要代码

new TaskSubscriber().start();

要发布的代码

TaskToRun task = new TaskToRun();
task.setData("send_sms");
FirebaseDatabase.getInstance().getReference().child("tasks").push().setValue(task);

0 个答案:

没有答案