Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

lua based ack implementation #3

Merged
merged 4 commits into from
Aug 24, 2017
Merged

Conversation

dvizelman
Copy link

No description provided.

try {
jedis.evalsha(this.LightKeeperScriptHash.get(), 1, getServerName());
} catch (RuntimeException e) {
e.printStackTrace();

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Please... never swallow an exception unless you have a very good reason to do so (almost never!).

Copy link
Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

You are right, will fix it. I made quick fix in order to see error message and forgot to re-throw exception

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

So please commit a fix, so the PR will be cleaner :)

}

public void activateLightKeeper() {
jedis.evalsha(this.RequeueJobsScriptHash.get(), 1, getServerName());

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Got it. Cool!!

protected final Jedis jedis;
private final ScheduledExecutorService scheduler =
Executors.newScheduledThreadPool(POOL_SIZE);
private final AtomicReference<String> LightKeeperScriptHash = new AtomicReference<>(null);

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Why do we need the AtomicReference?

Copy link
Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

While i can't see real need for AtomicReference in this case, I've followed the way scripts are loaded in WorkerImpl only as precaution and in order to save on consistency.

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Since it doesn't really have an affect, it's only confusing the reader.
I suggest to remove it.

@@ -615,7 +618,8 @@ private void removeInFlight(final String curQueue) {
if (SHUTDOWN_IMMEDIATE.equals(this.state.get())) {
lpoplpush(key(INFLIGHT, this.name, curQueue), key(QUEUE, curQueue));
} else {
this.jedis.lpop(key(INFLIGHT, this.name, curQueue));
this.jedis.evalsha(this.removeInFlightHash.get(), 2, key(INFLIGHT, this.name, curQueue),key("log"));

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

remove "this"

Copy link
Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Referencing instance variable thru this is the convention in this project, there are few other occurrences of this.jedis in this class. Why should we remove this exact reference that even was not introduced by us?

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

OK, makes sense :)

end


local function inspectLiveKeeper(currentTime)

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Why are you getting the currentTime from outside?

Copy link
Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Ohh !!! I'll give another look on it. Generally, I was not able to use any global variable unless it was defined before function that is going to use it . And I didn't wanted to call redis.time again and again

@@ -219,6 +221,7 @@ public void run() {
this.lpoplpushScriptHash.set(this.jedis.scriptLoad(ScriptUtils.readScript(LPOPLPUSH_LUA)));
this.multiPriorityQueuesScriptHash
.set(this.jedis.scriptLoad(ScriptUtils.readScript(POP_FROM_MULTIPLE_PRIO_QUEUES)));
this.removeInFlightHash.set(this.jedis.scriptLoad(ScriptUtils.readScript(REMOVE_INFLIGHT_LUA)));;

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Load the script only once.

Copy link
Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

remove in flight cache is loaded only once ...

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

OK, I see.


inspectLiveKeeper(currentTime);

redis.call('SET', isAliveKey,currentTime)

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

What is that?

Copy link
Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Updating is alive key every 2 sec on every server


local currentTime = getCurrentTime()

inspectLiveKeeper(currentTime);

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

When are we scheduling this to run every 5 seconds?

Copy link
Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Will be fixed

protected final Jedis jedis;
private final ScheduledExecutorService scheduler =
Executors.newScheduledThreadPool(POOL_SIZE);
private final AtomicReference<String> LightKeeperScriptHash = new AtomicReference<>(null);

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Since it doesn't really have an affect, it's only confusing the reader.
I suggest to remove it.

try {
jedis.evalsha(this.LightKeeperScriptHash.get(), 1, getServerName());
} catch (RuntimeException e) {
e.printStackTrace();

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

So please commit a fix, so the PR will be cleaner :)

@@ -615,7 +618,8 @@ private void removeInFlight(final String curQueue) {
if (SHUTDOWN_IMMEDIATE.equals(this.state.get())) {
lpoplpush(key(INFLIGHT, this.name, curQueue), key(QUEUE, curQueue));
} else {
this.jedis.lpop(key(INFLIGHT, this.name, curQueue));
this.jedis.evalsha(this.removeInFlightHash.get(), 2, key(INFLIGHT, this.name, curQueue),key("log"));

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

OK, makes sense :)

@@ -219,6 +221,7 @@ public void run() {
this.lpoplpushScriptHash.set(this.jedis.scriptLoad(ScriptUtils.readScript(LPOPLPUSH_LUA)));
this.multiPriorityQueuesScriptHash
.set(this.jedis.scriptLoad(ScriptUtils.readScript(POP_FROM_MULTIPLE_PRIO_QUEUES)));
this.removeInFlightHash.set(this.jedis.scriptLoad(ScriptUtils.readScript(REMOVE_INFLIGHT_LUA)));;

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

OK, I see.

}
}

public void activateLightKeeper() {

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

move to constructor...

Refactor lua scripts into one script providing all watchdog related functionality
} catch (RuntimeException e) {
LOG.error("Failed to run " + REQUEUE_JOBS + " job " + WATCHDOG_LUA + " script", e);
}

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

This method is doing too much and is a bit long... please break it down.

Copy link
Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Done

@dvizelman
Copy link
Author

dvizelman commented Aug 23, 2017

@nanimrod I feel like Watchdog needs to expose start method . just creating watchdog and expecting it to run automatically looks very unusual in code :


for (int i = 0; i < NUMBER_OF_WORKER_THREADS; i++) {
            final WorkerImpl worker = new WorkerImpl(
                    config,
                    Arrays.asList(HIGH.name(), LOW.name()),
                    redisJobService.getMapJobFactory(),
                    createJedis(config),
                    NextQueueStrategy.RESET_TO_HIGHEST_PRIORITY);
            final Thread workerThread = new Thread(worker);
            workerThread.start();
            workers.put(worker, workerThread);
        }

        new Watchdog(config, createJedis(config));

@dvizelman
Copy link
Author

I think the best would be to have start method just like Thread has.

@nanimrod
Copy link

I don't like a solution that forces the client to run 2 methods when none of them has any meaning without the other.

@dvizelman
Copy link
Author

What 2 methods are you talking about? 1 method start , that's all . And that's the standard behaviour for Java as you can see from the Thread example.

@dvizelman
Copy link
Author

If I need to choose between 2 bad solutions: having everything executed in constructor or having static method executing watchdog initialization logic, I will go with the constructor. At least in my tests I could extend watchdog with class having empty constructor and set it instead the original one. Just in case, few links bellow are discussing what's wrong with static methods in java

https://testing.googleblog.com/2008/12/static-methods-are-death-to-testability.html
https://simpleprogrammer.com/2010/01/29/static-methods-will-shock-you/
https://mrtnrbrts.wordpress.com/2012/01/18/static-methods-in-java-are-evil-mostly/

@dvizelman dvizelman merged commit 45f07bf into master Aug 24, 2017
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment
Labels
None yet
Projects
None yet
2 participants