1

I have a client server application and I'm using rxjava to do server requests from the client. The client should only do one request at a time so I intent to use a thread queue scheduler similar to the trampoline scheduler.

Now I try to implement a mechanism to watch changes on the server. Therefore I send a long living request that blocks until the server has some changes and sends back the result (long pull).

This long pull request should only run when the job queue is idle. I'm looking for a way to automatically stop the watch request when a regular request is scheduled and start it again when the queue becomes empty. I thought about modifying the trampoline scheduler to get this behavior but I have the feeling that this is a common problem and there might be an easier solution?

Clemens
  • 86
  • 8
  • Could you clarify the job queue a little bit? Where are they added from? Are these jobs sequential as well or can they build up? – lopar Jan 25 '15 at 22:58
  • don't completely understand your question, yes the jobs can build up but since they are in the queue they are handled sequentially... [code](https://github.com/czeidler/fejoajava/blob/master/src/main/java/org/fejoa/library/remote/RequestQueue.java) shows my current "solution". – Clemens Jan 27 '15 at 08:35
  • Side note: IMHO the better solution would to be to do parallel requests to the server. However, I'm using a PHP server and I had problems to do parallel requests from the same session (also session_write_close should allow that) I have to investigate that at some point and drop my current solution... – Clemens Jan 27 '15 at 08:46

1 Answers1

1

You can hold onto the Subscription returned by scheduling the long poll task, unsubscribe it if the queue becomes non-empty and re-schedule if the queue becomes empty.

Edit: here is an example with the basic ExecutorScheduler:

import java.util.concurrent.*;
import java.util.concurrent.atomic.*;


public class IdleScheduling {

    static final class TaskQueue {
        final ExecutorService executor;
        final AtomicReference<Future<?>> idleFuture;
        final Runnable idleRunnable;
        final AtomicInteger wip;
        public TaskQueue(Runnable idleRunnable) {
            this.executor = Executors.newFixedThreadPool(1);
            this.idleRunnable = idleRunnable;
            this.idleFuture = new AtomicReference<>();
            this.wip = new AtomicInteger();
            this.idleFuture.set(executor.submit(idleRunnable));
        }
        public void shutdownNow() {
            executor.shutdownNow();
        }
        public Future<?> enqueue(Runnable task) {
            if (wip.getAndIncrement() == 0) {
                idleFuture.get().cancel(true);
            }
            return executor.submit(() -> {
                task.run();
                if (wip.decrementAndGet() == 0) {
                    startIdle();
                }
            });
        }
        void startIdle() {
            idleFuture.set(executor.submit(idleRunnable));
        }
    }

    public static void main(String[] args) throws Exception {
        TaskQueue tq = new TaskQueue(() -> {
            while (!Thread.currentThread().isInterrupted()) {
                try {
                    Thread.sleep(1000);
                } catch (InterruptedException ex) {
                    System.out.println("Idle interrupted...");
                    return;
                }
                System.out.println("Idle...");
            }
        });
        try {
            Thread.sleep(1500);
            tq.enqueue(() -> System.out.println("Work 1"));
            Thread.sleep(500);
            tq.enqueue(() -> {
                System.out.println("Work 2");
                try {
                    Thread.sleep(500);
                } catch (InterruptedException ex) {

                }
            });
            tq.enqueue(() -> System.out.println("Work 3"));
            Thread.sleep(1500);
        } finally {
            tq.shutdownNow();
        }
    }
}
akarnokd
  • 69,132
  • 14
  • 157
  • 192
  • Thanks thats seems like a nice solution. However, I'm using rxjava for my jobs... I found a quite similar solution to yours that works with rxjava (see my comment above). – Clemens Mar 12 '15 at 07:12