├── src
├── main
│ └── java
│ │ └── biz
│ │ └── paluch
│ │ └── spinach
│ │ ├── package-info.java
│ │ ├── api
│ │ ├── package-info.java
│ │ ├── rx
│ │ │ ├── package-info.java
│ │ │ ├── DisqueReactiveCommands.java
│ │ │ ├── DisqueClusterReactiveCommands.java
│ │ │ └── DisqueQueueReactiveCommands.java
│ │ ├── async
│ │ │ ├── package-info.java
│ │ │ ├── DisqueAsyncCommands.java
│ │ │ ├── DisqueClusterAsyncCommands.java
│ │ │ └── DisqueQueueAsyncCommands.java
│ │ ├── sync
│ │ │ ├── package-info.java
│ │ │ ├── DisqueCommands.java
│ │ │ ├── DisqueClusterCommands.java
│ │ │ └── DisqueQueueCommands.java
│ │ ├── CommandKeyword.java
│ │ ├── CommandType.java
│ │ ├── Job.java
│ │ ├── DisqueConnection.java
│ │ ├── QScanArgs.java
│ │ ├── PauseArgs.java
│ │ └── JScanArgs.java
│ │ ├── output
│ │ ├── package-info.java
│ │ ├── SupportsObservables.java
│ │ ├── StringScanOutput.java
│ │ ├── JobOutput.java
│ │ ├── QstatMapOutput.java
│ │ └── JobListOutput.java
│ │ ├── cluster
│ │ ├── package-info.java
│ │ ├── GetJobsArgs.java
│ │ ├── DisqueNode.java
│ │ ├── NodeIdAwareSocketAddressSupplier.java
│ │ └── ClusterNodesParser.java
│ │ ├── impl
│ │ ├── package-info.java
│ │ ├── ConnectionAware.java
│ │ ├── EventExecutorAware.java
│ │ ├── SocketAddressSupplier.java
│ │ ├── BaseCommandBuilder.java
│ │ ├── DisqueCommand.java
│ │ ├── RoundRobin.java
│ │ ├── HelloClusterSocketAddressSupplier.java
│ │ ├── SocketAddressSupplierFactory.java
│ │ ├── RoundRobinSocketAddressSupplier.java
│ │ ├── FutureSyncInvocationHandler.java
│ │ ├── DisqueCommandArgs.java
│ │ └── ClusterAwareNodeSupport.java
│ │ └── SocketAddressResolver.java
├── test
│ ├── java
│ │ └── biz
│ │ │ └── paluch
│ │ │ └── spinach
│ │ │ ├── impl
│ │ │ ├── TestClusterAwareNodeSupport.java
│ │ │ ├── ClusterAwareNodeSupportTest.java
│ │ │ ├── AsyncCommandTest.java
│ │ │ └── DisqueCommandTest.java
│ │ │ ├── commands
│ │ │ ├── rx
│ │ │ │ ├── RxQueueCommandTest.java
│ │ │ │ ├── RxClusterCommandTest.java
│ │ │ │ ├── RxServerCommandTest.java
│ │ │ │ ├── RxJobCommandTest.java
│ │ │ │ └── RxSyncInvocationHandler.java
│ │ │ ├── BasicCommandTest.java
│ │ │ ├── AbstractCommandTest.java
│ │ │ └── ClusterCommandTest.java
│ │ │ ├── Example.java
│ │ │ ├── Sockets.java
│ │ │ ├── examples
│ │ │ ├── Standalone.java
│ │ │ └── PeriodicallyUpdatingSocketAddressSupplierFactory.java
│ │ │ ├── support
│ │ │ ├── FastShutdown.java
│ │ │ ├── TestClientResources.java
│ │ │ ├── DefaultDisqueClient.java
│ │ │ └── TestEventLoopGroupProvider.java
│ │ │ ├── ClusterConnectionTest.java
│ │ │ ├── RoundRobinSocketAddressSupplierTest.java
│ │ │ ├── UnixDomainSocketTest.java
│ │ │ ├── TestSettings.java
│ │ │ ├── cluster
│ │ │ └── ClusterNodesParserTest.java
│ │ │ ├── SslTest.java
│ │ │ ├── SyncAsyncApiConvergenceTest.java
│ │ │ └── ClientMetricsTest.java
│ └── resources
│ │ └── log4j.properties
├── assembly
│ ├── src.xml
│ └── bin.xml
└── site
│ ├── markdown
│ ├── index.md.vm
│ └── download.md.vm
│ └── site.xml
├── .gitignore
├── .travis.yml
├── .github
├── PULL_REQUEST_TEMPLATE.md
├── ISSUE_TEMPLATE.md
└── CONTRIBUTING.md
├── Makefile
└── README.md
/src/main/java/biz/paluch/spinach/package-info.java:
--------------------------------------------------------------------------------
1 | /**
2 | * Disque client.
3 | */
4 | package biz.paluch.spinach;
--------------------------------------------------------------------------------
/src/main/java/biz/paluch/spinach/api/package-info.java:
--------------------------------------------------------------------------------
1 | /**
2 | * Disque API.
3 | */
4 | package biz.paluch.spinach.api;
--------------------------------------------------------------------------------
/src/main/java/biz/paluch/spinach/output/package-info.java:
--------------------------------------------------------------------------------
1 | /**
2 | * Command output processors.
3 | */
4 | package biz.paluch.spinach.output;
5 |
6 |
--------------------------------------------------------------------------------
/src/main/java/biz/paluch/spinach/api/rx/package-info.java:
--------------------------------------------------------------------------------
1 | /**
2 | * Disque API for reactive executed commands.
3 | */
4 | package biz.paluch.spinach.api.rx;
--------------------------------------------------------------------------------
/src/main/java/biz/paluch/spinach/cluster/package-info.java:
--------------------------------------------------------------------------------
1 | /**
2 | * Support for Disque Cluster.
3 | */
4 | package biz.paluch.spinach.cluster;
5 |
6 |
--------------------------------------------------------------------------------
/src/main/java/biz/paluch/spinach/api/async/package-info.java:
--------------------------------------------------------------------------------
1 | /**
2 | * Disque API for asynchronous executed commands.
3 | */
4 | package biz.paluch.spinach.api.async;
--------------------------------------------------------------------------------
/src/main/java/biz/paluch/spinach/api/sync/package-info.java:
--------------------------------------------------------------------------------
1 | /**
2 | * Disque API for synchronous executed commands.
3 | */
4 | package biz.paluch.spinach.api.sync;
--------------------------------------------------------------------------------
/src/main/java/biz/paluch/spinach/impl/package-info.java:
--------------------------------------------------------------------------------
1 | /**
2 | * Disque implementation. API within this package can change at any time and without further notice.
3 | */
4 | package biz.paluch.spinach.impl;
--------------------------------------------------------------------------------
/.gitignore:
--------------------------------------------------------------------------------
1 | target/
2 | *.rdb
3 | *.aof
4 | nodes.conf
5 |
6 | -
7 | atlassian-ide-plugin.xml
8 | *.iml
9 | redis-git
10 | *.releaseBackup
11 | release.properties
12 | work/
13 | .project
14 | .classpath
15 | .settings
16 | dependency-reduced-pom.xml
17 | .idea
18 | Vagrantfile
19 | .vagrant
20 |
--------------------------------------------------------------------------------
/.travis.yml:
--------------------------------------------------------------------------------
1 | language: java
2 | jdk:
3 | - oraclejdk8
4 | sudo: false
5 | before_install:
6 | - if [[ ! -f stunnel.tar.gz ]]; then wget -O stunnel.tar.gz ftp://ftp.stunnel.org/stunnel/archive/5.x/stunnel-5.29.tar.gz; fi
7 | - if [[ ! -f ./stunnel-5.29/configure ]]; then tar -xzf stunnel.tar.gz; fi
8 | - if [[ ! -f ./stunnel-5.29/src/stunnel ]]; then cd ./stunnel-5.29; ./configure; make; cd ..; fi
9 | - export PATH="$PATH:$(pwd)/stunnel-5.29/src"
10 | install: make prepare ssl-keys
11 | script: make test-coveralls
12 | cache:
13 | directories:
14 | - '$HOME/.m2/repository'
15 | - '$TRAVIS_BUILD_DIR/stunnel-5.29'
16 |
--------------------------------------------------------------------------------
/.github/PULL_REQUEST_TEMPLATE.md:
--------------------------------------------------------------------------------
1 |
4 | Make sure that:
5 |
6 | - [ ] You have read the [contribution guidelines](https://github.com/mp911de/spinach/blob/master/.github/CONTRIBUTING.md).
7 | - [ ] You use the code formatters provided [here](https://github.com/mp911de/spinach/blob/master/formatting.xml) and have them applied to your changes. Don’t submit any formatting related changes.
8 | - [ ] You submit test cases (unit or integration tests) that back your changes.
9 |
10 |
13 |
--------------------------------------------------------------------------------
/.github/ISSUE_TEMPLATE.md:
--------------------------------------------------------------------------------
1 |
8 | Make sure that:
9 |
10 | - [ ] You have read the [contribution guidelines](https://github.com/mp911de/spinach/blob/master/.github/CONTRIBUTING.md).
11 | - [ ] You specify the spinach version and environment so it's obvious which version is affected
12 | - [ ] You provide a reproducible test case (either descriptive of as JUnit test) if it's a bug or the expected behavior differs from the actual behavior.
13 |
14 |
17 |
--------------------------------------------------------------------------------
/src/test/java/biz/paluch/spinach/impl/TestClusterAwareNodeSupport.java:
--------------------------------------------------------------------------------
1 | /*
2 | * Copyright 2016 the original author or authors.
3 | *
4 | * Licensed under the Apache License, Version 2.0 (the "License");
5 | * you may not use this file except in compliance with the License.
6 | * You may obtain a copy of the License at
7 | *
8 | * http://www.apache.org/licenses/LICENSE-2.0
9 | *
10 | * Unless required by applicable law or agreed to in writing, software
11 | * distributed under the License is distributed on an "AS IS" BASIS,
12 | * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
13 | * See the License for the specific language governing permissions and
14 | * limitations under the License.
15 | */
16 | package biz.paluch.spinach.impl;
17 |
18 | /**
19 | * @author Mark Paluch
20 | */
21 | public class TestClusterAwareNodeSupport extends ClusterAwareNodeSupport {
22 | }
--------------------------------------------------------------------------------
/src/test/resources/log4j.properties:
--------------------------------------------------------------------------------
1 | # Root logger option
2 | log4j.rootLogger=INFO, stdout, file
3 |
4 | # Direct log messages to stdout
5 | log4j.appender.stdout=org.apache.log4j.ConsoleAppender
6 | log4j.appender.stdout.Target=System.out
7 | log4j.appender.stdout.threshold=INFO
8 | log4j.appender.stdout.layout=org.apache.log4j.PatternLayout
9 | log4j.appender.stdout.layout.ConversionPattern=%d{yyyy-MM-dd HH:mm:ss} [%-5p] [%t] (%c{1}:%L) %m%n
10 |
11 | log4j.appender.file=org.apache.log4j.FileAppender
12 | log4j.appender.file.File=target/log.log
13 | log4j.appender.file.Append=false
14 | log4j.appender.file.layout=org.apache.log4j.PatternLayout
15 | log4j.appender.file.layout.ConversionPattern=%d{yyyy-MM-dd HH:mm:ss} [%-5p] [%t] (%c{1}:%L) %m%n
16 |
17 | log4j.logger.com.lambdaworks=INFO
18 | log4j.logger.biz.paluch.spinach=INFO
19 | log4j.logger.io.netty=INFO
20 | log4j.logger.com.lambdaworks.redis.protocol.ConnectionWatchdog=INFO
21 |
22 |
23 |
24 |
--------------------------------------------------------------------------------
/.github/CONTRIBUTING.md:
--------------------------------------------------------------------------------
1 | # Contributing to spinach
2 |
3 | If you would like to contribute code you can do so through GitHub by forking the repository and sending a pull request.
4 |
5 | When submitting code, please make every effort to follow existing conventions and style in order to keep the code as readable as possible.
6 | Formatting settings are provided for Eclipse in https://github.com/mp911de/spinach/blob/master/formatting.xml
7 |
8 | ## Bugreports
9 |
10 | If you report a bug, please ensure to specify the following:
11 |
12 | * spinach version (e.g. 0.1)
13 | * Contextual information (what were you trying to do using spinach)
14 | * Simplest possible steps to reproduce
15 | * JUnit tests to reproduce are great but not obligatory
16 |
17 | ## License
18 |
19 | By contributing your code, you agree to license your contribution under the terms of [Apache License 2.0] (http://www.apache.org/licenses/LICENSE-2.0).
20 |
21 | All files are released with the Apache 2.0 license.
22 |
--------------------------------------------------------------------------------
/src/assembly/src.xml:
--------------------------------------------------------------------------------
1 |
4 |
5 | src
6 |
7 | zip
8 | tar.gz
9 |
10 | ${project.version}-${project.version}-src
11 |
12 |
13 | src/main/java
14 | /
15 | true
16 |
17 |
18 | src/main/resources
19 | /
20 | true
21 |
22 |
23 |
--------------------------------------------------------------------------------
/src/test/java/biz/paluch/spinach/commands/rx/RxQueueCommandTest.java:
--------------------------------------------------------------------------------
1 | /*
2 | * Copyright 2016 the original author or authors.
3 | *
4 | * Licensed under the Apache License, Version 2.0 (the "License");
5 | * you may not use this file except in compliance with the License.
6 | * You may obtain a copy of the License at
7 | *
8 | * http://www.apache.org/licenses/LICENSE-2.0
9 | *
10 | * Unless required by applicable law or agreed to in writing, software
11 | * distributed under the License is distributed on an "AS IS" BASIS,
12 | * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
13 | * See the License for the specific language governing permissions and
14 | * limitations under the License.
15 | */
16 | package biz.paluch.spinach.commands.rx;
17 |
18 | import biz.paluch.spinach.commands.QueueCommandTest;
19 | import org.junit.Before;
20 |
21 | /**
22 | * @author Mark Paluch
23 | */
24 | public class RxQueueCommandTest extends QueueCommandTest {
25 |
26 | @Before
27 | public void openConnection() throws Exception {
28 | disque = RxSyncInvocationHandler.sync(client.connect());
29 | disque.debugFlushall();
30 | }
31 | }
32 |
--------------------------------------------------------------------------------
/src/test/java/biz/paluch/spinach/commands/rx/RxClusterCommandTest.java:
--------------------------------------------------------------------------------
1 | /*
2 | * Copyright 2016 the original author or authors.
3 | *
4 | * Licensed under the Apache License, Version 2.0 (the "License");
5 | * you may not use this file except in compliance with the License.
6 | * You may obtain a copy of the License at
7 | *
8 | * http://www.apache.org/licenses/LICENSE-2.0
9 | *
10 | * Unless required by applicable law or agreed to in writing, software
11 | * distributed under the License is distributed on an "AS IS" BASIS,
12 | * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
13 | * See the License for the specific language governing permissions and
14 | * limitations under the License.
15 | */
16 | package biz.paluch.spinach.commands.rx;
17 |
18 | import biz.paluch.spinach.commands.ClusterCommandTest;
19 | import org.junit.Before;
20 |
21 | import biz.paluch.spinach.commands.QueueCommandTest;
22 |
23 | /**
24 | * @author Mark Paluch
25 | */
26 | public class RxClusterCommandTest extends ClusterCommandTest {
27 |
28 | @Before
29 | public void openConnection() throws Exception {
30 | disque = RxSyncInvocationHandler.sync(client.connect());
31 | disque.debugFlushall();
32 | }
33 | }
34 |
--------------------------------------------------------------------------------
/src/main/java/biz/paluch/spinach/impl/ConnectionAware.java:
--------------------------------------------------------------------------------
1 | /*
2 | * Copyright 2016 the original author or authors.
3 | *
4 | * Licensed under the Apache License, Version 2.0 (the "License");
5 | * you may not use this file except in compliance with the License.
6 | * You may obtain a copy of the License at
7 | *
8 | * http://www.apache.org/licenses/LICENSE-2.0
9 | *
10 | * Unless required by applicable law or agreed to in writing, software
11 | * distributed under the License is distributed on an "AS IS" BASIS,
12 | * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
13 | * See the License for the specific language governing permissions and
14 | * limitations under the License.
15 | */
16 | package biz.paluch.spinach.impl;
17 |
18 | import biz.paluch.spinach.api.DisqueConnection;
19 |
20 | /**
21 | * Interface to be implemented by {@link SocketAddressSupplier} that want to be aware of their connection.
22 | *
23 | * @author Mark Paluch
24 | */
25 | public interface ConnectionAware {
26 |
27 | /**
28 | * Set the {@link DisqueConnection connection}.
29 | *
30 | * Invoked after activating and authenticating the connection.
31 | *
32 | * @param disqueConnection the connection
33 | * @param Key type
34 | * @param Value type
35 | */
36 | void setConnection(DisqueConnection disqueConnection);
37 | }
38 |
--------------------------------------------------------------------------------
/src/main/java/biz/paluch/spinach/impl/EventExecutorAware.java:
--------------------------------------------------------------------------------
1 | /*
2 | * Copyright 2016 the original author or authors.
3 | *
4 | * Licensed under the Apache License, Version 2.0 (the "License");
5 | * you may not use this file except in compliance with the License.
6 | * You may obtain a copy of the License at
7 | *
8 | * http://www.apache.org/licenses/LICENSE-2.0
9 | *
10 | * Unless required by applicable law or agreed to in writing, software
11 | * distributed under the License is distributed on an "AS IS" BASIS,
12 | * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
13 | * See the License for the specific language governing permissions and
14 | * limitations under the License.
15 | */
16 | package biz.paluch.spinach.impl;
17 |
18 | import io.netty.util.concurrent.EventExecutor;
19 |
20 | import java.util.concurrent.ScheduledExecutorService;
21 |
22 | /**
23 | * Interface to be implemented by {@link SocketAddressSupplier} that want to be aware of the {@link ScheduledExecutorService}.
24 | *
25 | * @author Mark Paluch
26 | */
27 | public interface EventExecutorAware {
28 |
29 | /**
30 | * Set the {@link ScheduledExecutorService event executor}. Invoked after activating and authenticating the connection.
31 | *
32 | * @param eventExecutor the eventExecutor
33 | */
34 | void setEventExecutor(ScheduledExecutorService eventExecutor);
35 | }
36 |
--------------------------------------------------------------------------------
/src/main/java/biz/paluch/spinach/output/SupportsObservables.java:
--------------------------------------------------------------------------------
1 | /*
2 | * Copyright 2016 the original author or authors.
3 | *
4 | * Licensed under the Apache License, Version 2.0 (the "License");
5 | * you may not use this file except in compliance with the License.
6 | * You may obtain a copy of the License at
7 | *
8 | * http://www.apache.org/licenses/LICENSE-2.0
9 | *
10 | * Unless required by applicable law or agreed to in writing, software
11 | * distributed under the License is distributed on an "AS IS" BASIS,
12 | * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
13 | * See the License for the specific language governing permissions and
14 | * limitations under the License.
15 | */
16 | package biz.paluch.spinach.output;
17 |
18 | import rx.Subscriber;
19 |
20 | /**
21 | * Facet interface that allows streaming support for {@link rx.Observable} result types. Implementors emit elements during
22 | * command parsing.
23 | *
24 | * @author Mark Paluch
25 | */
26 | public interface SupportsObservables {
27 |
28 | /**
29 | * Provide a subscriber for a certain output so results can be streamed to the subscriber in the moment of reception instead
30 | * of waiting for the command to finish.
31 | *
32 | * @param subscriber the subscriber
33 | * @param Result type
34 | */
35 | void setSubscriber(Subscriber subscriber);
36 | }
37 |
--------------------------------------------------------------------------------
/src/test/java/biz/paluch/spinach/commands/rx/RxServerCommandTest.java:
--------------------------------------------------------------------------------
1 | /*
2 | * Copyright 2016 the original author or authors.
3 | *
4 | * Licensed under the Apache License, Version 2.0 (the "License");
5 | * you may not use this file except in compliance with the License.
6 | * You may obtain a copy of the License at
7 | *
8 | * http://www.apache.org/licenses/LICENSE-2.0
9 | *
10 | * Unless required by applicable law or agreed to in writing, software
11 | * distributed under the License is distributed on an "AS IS" BASIS,
12 | * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
13 | * See the License for the specific language governing permissions and
14 | * limitations under the License.
15 | */
16 | package biz.paluch.spinach.commands.rx;
17 |
18 | import biz.paluch.spinach.commands.ServerCommandTest;
19 | import org.junit.Before;
20 | import org.junit.Test;
21 |
22 | /**
23 | * @author Mark Paluch
24 | */
25 | public class RxServerCommandTest extends ServerCommandTest {
26 |
27 | @Before
28 | public void openConnection() throws Exception {
29 | disque = RxSyncInvocationHandler.sync(client.connect());
30 | disque.debugFlushall();
31 | }
32 |
33 | // does not harm, because it's only executed when subscribing.
34 | @Test
35 | public void shutdown() throws Exception {
36 | disque.getConnection().reactive().shutdown(true);
37 | }
38 | }
39 |
--------------------------------------------------------------------------------
/src/test/java/biz/paluch/spinach/Example.java:
--------------------------------------------------------------------------------
1 | /*
2 | * Copyright 2016 the original author or authors.
3 | *
4 | * Licensed under the Apache License, Version 2.0 (the "License");
5 | * you may not use this file except in compliance with the License.
6 | * You may obtain a copy of the License at
7 | *
8 | * http://www.apache.org/licenses/LICENSE-2.0
9 | *
10 | * Unless required by applicable law or agreed to in writing, software
11 | * distributed under the License is distributed on an "AS IS" BASIS,
12 | * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
13 | * See the License for the specific language governing permissions and
14 | * limitations under the License.
15 | */
16 | package biz.paluch.spinach;
17 |
18 | import biz.paluch.spinach.api.DisqueConnection;
19 | import biz.paluch.spinach.api.sync.DisqueCommands;
20 |
21 | /**
22 | * @author Mark Paluch
23 | */
24 | public class Example {
25 |
26 | public static void main(String[] args) {
27 | String nodes = System.getenv("TYND_DISQUE_NODES");
28 | String auth = System.getenv("TYND_DISQUE_AUTH");
29 | DisqueClient disqueClient = new DisqueClient("disque://" + auth + "@" + nodes);
30 |
31 | DisqueCommands connection = disqueClient.connect().sync();
32 | System.out.println(connection.ping());
33 | connection.close();
34 | disqueClient.shutdown();
35 |
36 | }
37 | }
38 |
--------------------------------------------------------------------------------
/src/test/java/biz/paluch/spinach/Sockets.java:
--------------------------------------------------------------------------------
1 | /*
2 | * Copyright 2016 the original author or authors.
3 | *
4 | * Licensed under the Apache License, Version 2.0 (the "License");
5 | * you may not use this file except in compliance with the License.
6 | * You may obtain a copy of the License at
7 | *
8 | * http://www.apache.org/licenses/LICENSE-2.0
9 | *
10 | * Unless required by applicable law or agreed to in writing, software
11 | * distributed under the License is distributed on an "AS IS" BASIS,
12 | * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
13 | * See the License for the specific language governing permissions and
14 | * limitations under the License.
15 | */
16 | package biz.paluch.spinach;
17 |
18 | import java.io.IOException;
19 | import java.net.InetSocketAddress;
20 | import java.net.Socket;
21 | import java.util.concurrent.TimeUnit;
22 |
23 | /**
24 | * @author Mark Paluch
25 | */
26 | public class Sockets {
27 | public static boolean isOpen(String host, int port) {
28 | Socket socket = new Socket();
29 | try {
30 | socket.connect(new InetSocketAddress(host, port), (int) TimeUnit.MILLISECONDS.convert(1, TimeUnit.SECONDS));
31 | socket.close();
32 | return true;
33 | } catch (IOException e) {
34 | return false;
35 | }
36 | }
37 |
38 | private Sockets() {
39 | // unused
40 | }
41 | }
42 |
--------------------------------------------------------------------------------
/src/main/java/biz/paluch/spinach/output/StringScanOutput.java:
--------------------------------------------------------------------------------
1 | /*
2 | * Copyright 2016 the original author or authors.
3 | *
4 | * Licensed under the Apache License, Version 2.0 (the "License");
5 | * you may not use this file except in compliance with the License.
6 | * You may obtain a copy of the License at
7 | *
8 | * http://www.apache.org/licenses/LICENSE-2.0
9 | *
10 | * Unless required by applicable law or agreed to in writing, software
11 | * distributed under the License is distributed on an "AS IS" BASIS,
12 | * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
13 | * See the License for the specific language governing permissions and
14 | * limitations under the License.
15 | */
16 | package biz.paluch.spinach.output;
17 |
18 | import java.nio.ByteBuffer;
19 |
20 | import com.lambdaworks.redis.KeyScanCursor;
21 | import com.lambdaworks.redis.codec.RedisCodec;
22 | import com.lambdaworks.redis.output.ScanOutput;
23 |
24 | /**
25 | * Output handler for string-based {@code SCAN} commands.
26 | *
27 | * @param Key type.
28 | * @param Value type.
29 | * @author Mark Paluch
30 | */
31 | public class StringScanOutput extends ScanOutput> {
32 |
33 | public StringScanOutput(RedisCodec codec) {
34 | super(codec, new KeyScanCursor());
35 | }
36 |
37 | @Override
38 | protected void setOutput(ByteBuffer bytes) {
39 | output.getKeys().add(bytes == null ? null : decodeAscii(bytes));
40 | }
41 |
42 | }
43 |
--------------------------------------------------------------------------------
/src/main/java/biz/paluch/spinach/api/CommandKeyword.java:
--------------------------------------------------------------------------------
1 | /*
2 | * Copyright 2016 the original author or authors.
3 | *
4 | * Licensed under the Apache License, Version 2.0 (the "License");
5 | * you may not use this file except in compliance with the License.
6 | * You may obtain a copy of the License at
7 | *
8 | * http://www.apache.org/licenses/LICENSE-2.0
9 | *
10 | * Unless required by applicable law or agreed to in writing, software
11 | * distributed under the License is distributed on an "AS IS" BASIS,
12 | * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
13 | * See the License for the specific language governing permissions and
14 | * limitations under the License.
15 | */
16 | package biz.paluch.spinach.api;
17 |
18 | import com.lambdaworks.redis.protocol.LettuceCharsets;
19 | import com.lambdaworks.redis.protocol.ProtocolKeyword;
20 |
21 | /**
22 | * @author Mark Paluch
23 | */
24 | public enum CommandKeyword implements ProtocolKeyword {
25 |
26 | ALL, ASYNC, BCAST, BLOCKING, BUSYLOOP, COUNT, DELAY, FLUSHALL, FORGET, FROM, GET, HARD, ID, IMPORTRATE, IN, LEAVING,
27 |
28 | MAXLEN, MEET, MINLEN, NODES, NOHANG, NONE, OUT, QUEUE, REPLICATE, REPLY, RESET, RESETSTAT, RETRY,
29 |
30 | REWRITE, SAVECONFIG, SET, SOFT, STATE, TIMEOUT, TTL, WITHCOUNTERS;
31 |
32 | public final byte[] bytes;
33 |
34 | private CommandKeyword() {
35 | bytes = name().getBytes(LettuceCharsets.ASCII);
36 | }
37 |
38 | @Override
39 | public byte[] getBytes() {
40 | return bytes;
41 | }
42 | }
43 |
--------------------------------------------------------------------------------
/src/main/java/biz/paluch/spinach/impl/SocketAddressSupplier.java:
--------------------------------------------------------------------------------
1 | /*
2 | * Copyright 2016 the original author or authors.
3 | *
4 | * Licensed under the Apache License, Version 2.0 (the "License");
5 | * you may not use this file except in compliance with the License.
6 | * You may obtain a copy of the License at
7 | *
8 | * http://www.apache.org/licenses/LICENSE-2.0
9 | *
10 | * Unless required by applicable law or agreed to in writing, software
11 | * distributed under the License is distributed on an "AS IS" BASIS,
12 | * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
13 | * See the License for the specific language governing permissions and
14 | * limitations under the License.
15 | */
16 | package biz.paluch.spinach.impl;
17 |
18 | import java.net.SocketAddress;
19 | import java.util.function.Supplier;
20 |
21 | /**
22 | * Supplier API for {@link SocketAddress}. A {@code SocketAddressSupplier} is typically used to provide a {@link SocketAddress}
23 | * for connecting to Disque. The client requests a socket address from the supplier to establish initially a connection or to
24 | * reconnect. The supplier is required to supply an infinite number of elements. The sequence and ordering of elements are a
25 | * detail of the particular implementation.
26 | *
27 | * {@link SocketAddressSupplier} instances should not be shared between connections although this is possible.
28 | *
29 | *
30 | * @author Mark Paluch
31 | * @since 0.3
32 | */
33 | public interface SocketAddressSupplier extends Supplier {
34 |
35 | }
36 |
--------------------------------------------------------------------------------
/src/test/java/biz/paluch/spinach/examples/Standalone.java:
--------------------------------------------------------------------------------
1 | /*
2 | * Copyright 2016 the original author or authors.
3 | *
4 | * Licensed under the Apache License, Version 2.0 (the "License");
5 | * you may not use this file except in compliance with the License.
6 | * You may obtain a copy of the License at
7 | *
8 | * http://www.apache.org/licenses/LICENSE-2.0
9 | *
10 | * Unless required by applicable law or agreed to in writing, software
11 | * distributed under the License is distributed on an "AS IS" BASIS,
12 | * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
13 | * See the License for the specific language governing permissions and
14 | * limitations under the License.
15 | */
16 | package biz.paluch.spinach.examples;
17 |
18 | import java.util.concurrent.TimeUnit;
19 |
20 | import biz.paluch.spinach.DisqueClient;
21 | import biz.paluch.spinach.DisqueURI;
22 | import biz.paluch.spinach.api.Job;
23 | import biz.paluch.spinach.api.sync.DisqueCommands;
24 |
25 | /**
26 | * @author Mark Paluch
27 | */
28 | public class Standalone {
29 |
30 | public static void main(String[] args) {
31 | DisqueClient disqueClient = DisqueClient.create(DisqueURI.create("disque://password@localhost:7711"));
32 | DisqueCommands sync = disqueClient.connect().sync();
33 |
34 | sync.addjob("queue", "body", 1, TimeUnit.MINUTES);
35 |
36 | Job job = sync.getjob("queue");
37 |
38 | sync.ackjob(job.getId());
39 |
40 | sync.close();
41 | disqueClient.shutdown();
42 | }
43 | }
44 |
--------------------------------------------------------------------------------
/src/main/java/biz/paluch/spinach/impl/BaseCommandBuilder.java:
--------------------------------------------------------------------------------
1 | /*
2 | * Copyright 2016 the original author or authors.
3 | *
4 | * Licensed under the Apache License, Version 2.0 (the "License");
5 | * you may not use this file except in compliance with the License.
6 | * You may obtain a copy of the License at
7 | *
8 | * http://www.apache.org/licenses/LICENSE-2.0
9 | *
10 | * Unless required by applicable law or agreed to in writing, software
11 | * distributed under the License is distributed on an "AS IS" BASIS,
12 | * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
13 | * See the License for the specific language governing permissions and
14 | * limitations under the License.
15 | */
16 | package biz.paluch.spinach.impl;
17 |
18 | import com.lambdaworks.redis.codec.RedisCodec;
19 | import com.lambdaworks.redis.output.CommandOutput;
20 | import com.lambdaworks.redis.protocol.Command;
21 | import com.lambdaworks.redis.protocol.ProtocolKeyword;
22 |
23 | class BaseCommandBuilder {
24 | protected RedisCodec codec;
25 |
26 | public BaseCommandBuilder(RedisCodec codec) {
27 | this.codec = codec;
28 | }
29 |
30 | protected Command createCommand(ProtocolKeyword type, CommandOutput output) {
31 | return createCommand(type, output, null);
32 | }
33 |
34 | protected Command createCommand(ProtocolKeyword type, CommandOutput output,
35 | DisqueCommandArgs args) {
36 | return new DisqueCommand(type, output, args);
37 | }
38 |
39 | }
--------------------------------------------------------------------------------
/src/main/java/biz/paluch/spinach/api/CommandType.java:
--------------------------------------------------------------------------------
1 | /*
2 | * Copyright 2016 the original author or authors.
3 | *
4 | * Licensed under the Apache License, Version 2.0 (the "License");
5 | * you may not use this file except in compliance with the License.
6 | * You may obtain a copy of the License at
7 | *
8 | * http://www.apache.org/licenses/LICENSE-2.0
9 | *
10 | * Unless required by applicable law or agreed to in writing, software
11 | * distributed under the License is distributed on an "AS IS" BASIS,
12 | * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
13 | * See the License for the specific language governing permissions and
14 | * limitations under the License.
15 | */
16 | package biz.paluch.spinach.api;
17 |
18 | import com.lambdaworks.redis.protocol.LettuceCharsets;
19 | import com.lambdaworks.redis.protocol.ProtocolKeyword;
20 |
21 | /**
22 | * @author Mark Paluch
23 | */
24 | public enum CommandType implements ProtocolKeyword {
25 | // Jobs
26 | ADDJOB, ACKJOB, DELJOB, FASTACK, GETJOB, JSCAN, SHOW,
27 |
28 | // Queues
29 | ENQUEUE, DEQUEUE, NACK, PAUSE, QLEN, QPEEK, QSCAN, QSTAT, WORKING,
30 |
31 | // AOF
32 | BGREWRITEAOF,
33 |
34 | // Server commands
35 | AUTH, CONFIG, CLUSTER, CLIENT, COMMAND, DEBUG, INFO, /* LATENCY, */HELLO, PING, QUIT, SHUTDOWN, SLOWLOG, TIME;
36 |
37 | public final byte[] bytes;
38 |
39 | CommandType() {
40 | bytes = name().getBytes(LettuceCharsets.ASCII);
41 | }
42 |
43 | @Override
44 | public byte[] getBytes() {
45 | return bytes;
46 | }
47 |
48 | }
49 |
--------------------------------------------------------------------------------
/src/test/java/biz/paluch/spinach/support/FastShutdown.java:
--------------------------------------------------------------------------------
1 | /*
2 | * Copyright 2016 the original author or authors.
3 | *
4 | * Licensed under the Apache License, Version 2.0 (the "License");
5 | * you may not use this file except in compliance with the License.
6 | * You may obtain a copy of the License at
7 | *
8 | * http://www.apache.org/licenses/LICENSE-2.0
9 | *
10 | * Unless required by applicable law or agreed to in writing, software
11 | * distributed under the License is distributed on an "AS IS" BASIS,
12 | * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
13 | * See the License for the specific language governing permissions and
14 | * limitations under the License.
15 | */
16 | package biz.paluch.spinach.support;
17 |
18 | import java.util.concurrent.TimeUnit;
19 |
20 | import com.lambdaworks.redis.AbstractRedisClient;
21 | import com.lambdaworks.redis.resource.ClientResources;
22 |
23 | /**
24 | * @author Mark Paluch
25 | */
26 | public class FastShutdown {
27 |
28 | /**
29 | * Shut down a {@link AbstractRedisClient} with a timeout of 10ms.
30 | *
31 | * @param redisClient
32 | */
33 | public static void shutdown(AbstractRedisClient redisClient) {
34 | redisClient.shutdown(10, 10, TimeUnit.MILLISECONDS);
35 | }
36 |
37 | /**
38 | * Shut down a {@link ClientResources} client with a timeout of 10ms.
39 | *
40 | * @param clientResources
41 | */
42 | public static void shutdown(ClientResources clientResources) {
43 | clientResources.shutdown(10, 10, TimeUnit.MILLISECONDS);
44 | }
45 | }
46 |
--------------------------------------------------------------------------------
/src/test/java/biz/paluch/spinach/impl/ClusterAwareNodeSupportTest.java:
--------------------------------------------------------------------------------
1 | /*
2 | * Copyright 2016 the original author or authors.
3 | *
4 | * Licensed under the Apache License, Version 2.0 (the "License");
5 | * you may not use this file except in compliance with the License.
6 | * You may obtain a copy of the License at
7 | *
8 | * http://www.apache.org/licenses/LICENSE-2.0
9 | *
10 | * Unless required by applicable law or agreed to in writing, software
11 | * distributed under the License is distributed on an "AS IS" BASIS,
12 | * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
13 | * See the License for the specific language governing permissions and
14 | * limitations under the License.
15 | */
16 | package biz.paluch.spinach.impl;
17 |
18 | import biz.paluch.spinach.api.DisqueConnection;
19 | import biz.paluch.spinach.cluster.DisqueNode;
20 | import biz.paluch.spinach.commands.AbstractCommandTest;
21 | import org.junit.Test;
22 |
23 | import java.util.List;
24 |
25 | import static org.assertj.core.api.Assertions.assertThat;
26 |
27 | /**
28 | * @author Mark Paluch
29 | */
30 | public class ClusterAwareNodeSupportTest extends AbstractCommandTest {
31 |
32 | private TestClusterAwareNodeSupport sut = new TestClusterAwareNodeSupport();
33 |
34 | @Test
35 | public void testClusterView() throws Exception {
36 |
37 | sut.setConnection(disque.getConnection());
38 | sut.reloadNodes();
39 |
40 | List nodes = sut.getNodes();
41 | assertThat(nodes.size()).isGreaterThan(1);
42 | assertThat(nodes.get(0).getPort()).isEqualTo(port);
43 | assertThat(nodes.get(0).getAddr()).isNotNull();
44 | assertThat(nodes.get(0).getNodeId()).isNotNull();
45 | }
46 | }
--------------------------------------------------------------------------------
/src/main/java/biz/paluch/spinach/cluster/GetJobsArgs.java:
--------------------------------------------------------------------------------
1 | /*
2 | * Copyright 2016 the original author or authors.
3 | *
4 | * Licensed under the Apache License, Version 2.0 (the "License");
5 | * you may not use this file except in compliance with the License.
6 | * You may obtain a copy of the License at
7 | *
8 | * http://www.apache.org/licenses/LICENSE-2.0
9 | *
10 | * Unless required by applicable law or agreed to in writing, software
11 | * distributed under the License is distributed on an "AS IS" BASIS,
12 | * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
13 | * See the License for the specific language governing permissions and
14 | * limitations under the License.
15 | */
16 | package biz.paluch.spinach.cluster;
17 |
18 | import java.util.concurrent.TimeUnit;
19 |
20 | /**
21 | * @author Mark Paluch
22 | */
23 | class GetJobsArgs {
24 |
25 | private final long timeout;
26 | private final TimeUnit timeUnit;
27 | private final long count;
28 | private final Q[] queues;
29 |
30 | public static GetJobsArgs create(long timeout, TimeUnit timeUnit, long count, Q[] queues) {
31 | return new GetJobsArgs(timeout, timeUnit, count, queues);
32 | }
33 |
34 | GetJobsArgs(long timeout, TimeUnit timeUnit, long count, Q[] queues) {
35 | this.timeout = timeout;
36 | this.timeUnit = timeUnit;
37 | this.count = count;
38 | this.queues = queues;
39 | }
40 |
41 | public long getTimeout() {
42 | return timeout;
43 | }
44 |
45 | public TimeUnit getTimeUnit() {
46 | return timeUnit;
47 | }
48 |
49 | public long getCount() {
50 | return count;
51 | }
52 |
53 | public Q[] getQueues() {
54 | return queues;
55 | }
56 | }
57 |
--------------------------------------------------------------------------------
/src/main/java/biz/paluch/spinach/impl/DisqueCommand.java:
--------------------------------------------------------------------------------
1 | /*
2 | * Copyright 2016 the original author or authors.
3 | *
4 | * Licensed under the Apache License, Version 2.0 (the "License");
5 | * you may not use this file except in compliance with the License.
6 | * You may obtain a copy of the License at
7 | *
8 | * http://www.apache.org/licenses/LICENSE-2.0
9 | *
10 | * Unless required by applicable law or agreed to in writing, software
11 | * distributed under the License is distributed on an "AS IS" BASIS,
12 | * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
13 | * See the License for the specific language governing permissions and
14 | * limitations under the License.
15 | */
16 | package biz.paluch.spinach.impl;
17 |
18 | import java.util.concurrent.ExecutionException;
19 | import java.util.concurrent.TimeUnit;
20 | import java.util.concurrent.TimeoutException;
21 |
22 | import com.lambdaworks.redis.RedisCommandExecutionException;
23 | import com.lambdaworks.redis.RedisCommandInterruptedException;
24 | import com.lambdaworks.redis.output.CommandOutput;
25 | import com.lambdaworks.redis.protocol.Command;
26 | import com.lambdaworks.redis.protocol.ProtocolKeyword;
27 |
28 | /**
29 | * Command based on the original lettuce command but the command throws a {@link RedisCommandExecutionException} if Disque
30 | * reports an error while command execution.
31 | *
32 | * @author Mark Paluch
33 | */
34 | class DisqueCommand extends Command {
35 |
36 | public DisqueCommand(ProtocolKeyword type, CommandOutput output, DisqueCommandArgs args) {
37 | super(type, output, args);
38 | }
39 |
40 | @Override
41 | public DisqueCommandArgs getArgs() {
42 | return (DisqueCommandArgs) super.getArgs();
43 | }
44 |
45 | }
46 |
--------------------------------------------------------------------------------
/src/test/java/biz/paluch/spinach/impl/AsyncCommandTest.java:
--------------------------------------------------------------------------------
1 | /*
2 | * Copyright 2016 the original author or authors.
3 | *
4 | * Licensed under the Apache License, Version 2.0 (the "License");
5 | * you may not use this file except in compliance with the License.
6 | * You may obtain a copy of the License at
7 | *
8 | * http://www.apache.org/licenses/LICENSE-2.0
9 | *
10 | * Unless required by applicable law or agreed to in writing, software
11 | * distributed under the License is distributed on an "AS IS" BASIS,
12 | * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
13 | * See the License for the specific language governing permissions and
14 | * limitations under the License.
15 | */
16 | package biz.paluch.spinach.impl;
17 |
18 | import static org.assertj.core.api.Assertions.*;
19 |
20 | import java.util.concurrent.ExecutionException;
21 | import java.util.concurrent.TimeUnit;
22 |
23 | import com.lambdaworks.redis.protocol.AsyncCommand;
24 | import org.junit.Test;
25 |
26 | import biz.paluch.spinach.commands.AbstractCommandTest;
27 |
28 | import com.lambdaworks.redis.RedisCommandExecutionException;
29 | import com.lambdaworks.redis.RedisFuture;
30 |
31 | /**
32 | * @author Mark Paluch
33 | * @since 24.06.15 09:04
34 | */
35 | public class AsyncCommandTest extends AbstractCommandTest {
36 |
37 | @Test(expected = ExecutionException.class)
38 | public void asyncThrowsExecutionException() throws Exception {
39 | disque.getConnection().async().clientKill("do not exist").get();
40 | }
41 |
42 | @Test
43 | public void testAsyncCommand() throws Exception {
44 | RedisFuture ping = disque.getConnection().async().ping();
45 | assertThat(ping).isInstanceOf(AsyncCommand.class);
46 | assertThat(ping.isCancelled()).isFalse();
47 | assertThat(ping.getError()).isNull();
48 | assertThat(ping.get(1, TimeUnit.MINUTES)).isEqualTo("PONG");
49 |
50 | }
51 |
52 | }
53 |
--------------------------------------------------------------------------------
/src/main/java/biz/paluch/spinach/api/Job.java:
--------------------------------------------------------------------------------
1 | /*
2 | * Copyright 2016 the original author or authors.
3 | *
4 | * Licensed under the Apache License, Version 2.0 (the "License");
5 | * you may not use this file except in compliance with the License.
6 | * You may obtain a copy of the License at
7 | *
8 | * http://www.apache.org/licenses/LICENSE-2.0
9 | *
10 | * Unless required by applicable law or agreed to in writing, software
11 | * distributed under the License is distributed on an "AS IS" BASIS,
12 | * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
13 | * See the License for the specific language governing permissions and
14 | * limitations under the License.
15 | */
16 | package biz.paluch.spinach.api;
17 |
18 | import java.util.Map;
19 |
20 | /**
21 | * Disque Job data structure.
22 | *
23 | * @author Mark Paluch
24 | * @param Queue-Id Type.
25 | * @param Body-Id Type.
26 | */
27 | public class Job {
28 | private K queue;
29 | private String id;
30 | private V body;
31 | private Map counters;
32 |
33 | protected Job() {
34 | }
35 |
36 | public Job(K queue, String id, V body, Map counters) {
37 | this.queue = queue;
38 | this.id = id;
39 | this.body = body;
40 | this.counters = counters;
41 | }
42 |
43 | /**
44 | *
45 | * @return the queue
46 | */
47 | public K getQueue() {
48 | return queue;
49 | }
50 |
51 | /**
52 | *
53 | * @return the JobId
54 | */
55 | public String getId() {
56 | return id;
57 | }
58 |
59 | /**
60 | *
61 | * @return the Job body
62 | */
63 | public V getBody() {
64 | return body;
65 | }
66 |
67 | /**
68 | * If requested with a WITHCOUNTERS flag, getjob also populates a counters field.
69 | *
70 | * @return map of counters
71 | */
72 | public Map getCounters() { return counters; }
73 | }
74 |
--------------------------------------------------------------------------------
/src/test/java/biz/paluch/spinach/support/TestClientResources.java:
--------------------------------------------------------------------------------
1 | /*
2 | * Copyright 2016 the original author or authors.
3 | *
4 | * Licensed under the Apache License, Version 2.0 (the "License");
5 | * you may not use this file except in compliance with the License.
6 | * You may obtain a copy of the License at
7 | *
8 | * http://www.apache.org/licenses/LICENSE-2.0
9 | *
10 | * Unless required by applicable law or agreed to in writing, software
11 | * distributed under the License is distributed on an "AS IS" BASIS,
12 | * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
13 | * See the License for the specific language governing permissions and
14 | * limitations under the License.
15 | */
16 | package biz.paluch.spinach.support;
17 |
18 | import java.util.concurrent.TimeUnit;
19 |
20 | import com.lambdaworks.redis.resource.ClientResources;
21 | import com.lambdaworks.redis.resource.DefaultClientResources;
22 |
23 | /**
24 | * Client-Resources suitable for testing. Uses {@link TestEventLoopGroupProvider} to preserve the event
25 | * loop groups between tests. Every time a new {@link TestClientResources} instance is created, shutdown hook is added
26 | * {@link Runtime#addShutdownHook(Thread)}.
27 | *
28 | * @author Mark Paluch
29 | */
30 | public class TestClientResources {
31 |
32 | public static ClientResources create() {
33 | final DefaultClientResources resources = new DefaultClientResources.Builder().eventLoopGroupProvider(
34 | new TestEventLoopGroupProvider()).build();
35 |
36 | Runtime.getRuntime().addShutdownHook(new Thread() {
37 | @Override
38 | public void run() {
39 | try {
40 | resources.shutdown(100, 100, TimeUnit.MILLISECONDS).get(10, TimeUnit.SECONDS);
41 | } catch (Exception e) {
42 | e.printStackTrace();
43 | }
44 | }
45 | });
46 |
47 | return resources;
48 | }
49 | }
50 |
--------------------------------------------------------------------------------
/src/main/java/biz/paluch/spinach/SocketAddressResolver.java:
--------------------------------------------------------------------------------
1 | /*
2 | * Copyright 2016 the original author or authors.
3 | *
4 | * Licensed under the Apache License, Version 2.0 (the "License");
5 | * you may not use this file except in compliance with the License.
6 | * You may obtain a copy of the License at
7 | *
8 | * http://www.apache.org/licenses/LICENSE-2.0
9 | *
10 | * Unless required by applicable law or agreed to in writing, software
11 | * distributed under the License is distributed on an "AS IS" BASIS,
12 | * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
13 | * See the License for the specific language governing permissions and
14 | * limitations under the License.
15 | */
16 |
17 | package biz.paluch.spinach;
18 |
19 | import java.net.InetAddress;
20 | import java.net.InetSocketAddress;
21 | import java.net.SocketAddress;
22 | import java.net.UnknownHostException;
23 |
24 | import com.lambdaworks.redis.ConnectionPoint;
25 | import com.lambdaworks.redis.resource.DnsResolver;
26 |
27 | /**
28 | * Resolves a {@link com.lambdaworks.redis.RedisURI} to a {@link java.net.SocketAddress}.
29 | *
30 | * @author Mark Paluch
31 | */
32 | class SocketAddressResolver {
33 |
34 | /**
35 | * Resolves a {@link ConnectionPoint} to a {@link java.net.SocketAddress}.
36 | *
37 | * @param inetSocketAddress must not be {@literal null}
38 | * @param dnsResolver must not be {@literal null}
39 | * @return the resolved {@link SocketAddress}
40 | */
41 | public static SocketAddress resolve(InetSocketAddress inetSocketAddress, DnsResolver dnsResolver) {
42 |
43 | try {
44 | InetAddress inetAddress = dnsResolver.resolve(inetSocketAddress.getHostString())[0];
45 | return new InetSocketAddress(inetAddress, inetSocketAddress.getPort());
46 | } catch (UnknownHostException e) {
47 | return new InetSocketAddress(inetSocketAddress.getHostString(), inetSocketAddress.getPort());
48 | }
49 |
50 | }
51 | }
--------------------------------------------------------------------------------
/src/main/java/biz/paluch/spinach/impl/RoundRobin.java:
--------------------------------------------------------------------------------
1 | /*
2 | * Copyright 2016 the original author or authors.
3 | *
4 | * Licensed under the Apache License, Version 2.0 (the "License");
5 | * you may not use this file except in compliance with the License.
6 | * You may obtain a copy of the License at
7 | *
8 | * http://www.apache.org/licenses/LICENSE-2.0
9 | *
10 | * Unless required by applicable law or agreed to in writing, software
11 | * distributed under the License is distributed on an "AS IS" BASIS,
12 | * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
13 | * See the License for the specific language governing permissions and
14 | * limitations under the License.
15 | */
16 | package biz.paluch.spinach.impl;
17 |
18 | import java.util.Collection;
19 |
20 | /**
21 | * Circular element provider. This class allows infinite scrolling over a collection with the possibility to provide an initial
22 | * offset.
23 | *
24 | * @author Mark Paluch
25 | */
26 | public class RoundRobin {
27 |
28 | protected final Collection extends V> collection;
29 | protected V offset;
30 |
31 | public RoundRobin(Collection extends V> collection) {
32 | this(collection, null);
33 | }
34 |
35 | public RoundRobin(Collection extends V> collection, V offset) {
36 | this.collection = collection;
37 | this.offset = offset;
38 | }
39 |
40 | /**
41 | * Returns the next item.
42 | *
43 | * @return the next item
44 | */
45 | public V next() {
46 | if (offset != null) {
47 | boolean accept = false;
48 | for (V element : collection) {
49 | if (element == offset) {
50 | accept = true;
51 | continue;
52 | }
53 |
54 | if (accept) {
55 | return offset = element;
56 | }
57 | }
58 | }
59 |
60 | return offset = collection.iterator().next();
61 | }
62 |
63 | }
64 |
--------------------------------------------------------------------------------
/src/site/markdown/index.md.vm:
--------------------------------------------------------------------------------
1 | spinach - A scalable Java Disque client
2 | =============
3 |
4 | Spinach is a scalable thread-safe Disque client providing both synchronous and
5 | asynchronous APIs. Multiple threads may share one connection if they do not use blocking commands. Spinach is based on
6 | [lettuce](https://github.com/mp911de/lettuce).
7 | Multiple connections are efficiently managed by the excellent netty NIO
8 | framework.
9 |
10 | * Works with Java 6, 7 and 8
11 | * [synchronous](https://github.com/mp911de/spinach/wiki/Basic-usage), [asynchronous](https://github.com/mp911de/spinach/wiki/Asynchronous-API) and [reactive](https://github.com/mp911de/spinach/wiki/Reactive-API) APIs
12 | * [SSL](https://github.com/mp911de/spinach/wiki/SSL-Connections) and [Unix Domain Socket](https://github.com/mp911de/spinach/wiki/Unix-Domain-Sockets) connections
13 | * [Codecs](https://github.com/mp911de/lettuce/wiki/Codecs) (for UTF8/bit/JSON etc. representation of your data)
14 |
15 | See the [Wiki](https://github.com/mp911de/spinach/wiki) for more docs.
16 |
17 |
18 | Communication
19 | ---------------
20 |
21 | * [Github Issues](https://github.com/mp911de/spinach/issues)
22 |
23 |
24 | Documentation
25 | ---------------
26 |
27 | * [Wiki](https://github.com/mp911de/spinach/wiki)
28 | * [Javadoc](http://spinach.paluch.biz/apidocs/)
29 |
30 | Binaries/Download
31 | ----------------
32 |
33 | Binaries and dependency information for Maven, Ivy, Gradle and others can be found at http://search.maven.org.
34 |
35 | Releases of spinach are available in the maven central repository. Take also a look at the [Download](https://github.com/mp911de/spinach/wiki/Download) page in the [Wiki](https://github.com/mp911de/lettuce/wiki).
36 |
37 | Example for Maven:
38 |
39 | ```xml
40 |
41 | biz.paluch.redis
42 | spinach
43 | ${spinach-release-version}
44 |
45 | ```
46 |
47 | All versions: [Maven Central](http://search.maven.org/#search%7Cga%7C1%7Cg%3A%22biz.paluch.redis%22%20AND%20a%3A%spinach%22)
48 |
49 | Snapshots: [Sonatype OSS Repository](https://oss.sonatype.org/#nexus-search;gav~biz.paluch.redis~spinach~~~)
50 |
51 |
--------------------------------------------------------------------------------
/src/main/java/biz/paluch/spinach/api/rx/DisqueReactiveCommands.java:
--------------------------------------------------------------------------------
1 | /*
2 | * Copyright 2016 the original author or authors.
3 | *
4 | * Licensed under the Apache License, Version 2.0 (the "License");
5 | * you may not use this file except in compliance with the License.
6 | * You may obtain a copy of the License at
7 | *
8 | * http://www.apache.org/licenses/LICENSE-2.0
9 | *
10 | * Unless required by applicable law or agreed to in writing, software
11 | * distributed under the License is distributed on an "AS IS" BASIS,
12 | * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
13 | * See the License for the specific language governing permissions and
14 | * limitations under the License.
15 | */
16 | package biz.paluch.spinach.api.rx;
17 |
18 | import rx.Observable;
19 | import biz.paluch.spinach.api.DisqueConnection;
20 |
21 | /**
22 | * Reactive commands for Disque. This API is thread-safe.
23 | *
24 | * @param Key type.
25 | * @param Value type.
26 | * @author Mark Paluch
27 | */
28 | public interface DisqueReactiveCommands extends DisqueJobReactiveCommands, DisqueQueueReactiveCommands,
29 | DisqueServerReactiveCommands, DisqueClusterReactiveCommands {
30 |
31 | /**
32 | * Authenticate to the server.
33 | *
34 | * @param password the password
35 | * @return String simple-string-reply
36 | */
37 | Observable auth(String password);
38 |
39 | /**
40 | * Close the connection. The connection will become not usable anymore as soon as this method was called.
41 | */
42 | void close();
43 |
44 | /**
45 | *
46 | * @return the underlying connection.
47 | */
48 | DisqueConnection getConnection();
49 |
50 | /**
51 | *
52 | * @return true if the connection is open (connected and not closed).
53 | */
54 | boolean isOpen();
55 |
56 | /**
57 | * Ping the server.
58 | *
59 | * @return simple-string-reply
60 | */
61 | Observable ping();
62 |
63 | /**
64 | * Close the connection.
65 | *
66 | * @return String simple-string-reply always OK.
67 | */
68 | Observable quit();
69 |
70 | }
71 |
--------------------------------------------------------------------------------
/src/test/java/biz/paluch/spinach/ClusterConnectionTest.java:
--------------------------------------------------------------------------------
1 | /*
2 | * Copyright 2016 the original author or authors.
3 | *
4 | * Licensed under the Apache License, Version 2.0 (the "License");
5 | * you may not use this file except in compliance with the License.
6 | * You may obtain a copy of the License at
7 | *
8 | * http://www.apache.org/licenses/LICENSE-2.0
9 | *
10 | * Unless required by applicable law or agreed to in writing, software
11 | * distributed under the License is distributed on an "AS IS" BASIS,
12 | * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
13 | * See the License for the specific language governing permissions and
14 | * limitations under the License.
15 | */
16 | package biz.paluch.spinach;
17 |
18 | import static biz.paluch.spinach.TestSettings.host;
19 | import static biz.paluch.spinach.TestSettings.port;
20 | import static org.assertj.core.api.Assertions.assertThat;
21 |
22 | import org.junit.AfterClass;
23 | import org.junit.BeforeClass;
24 | import org.junit.Test;
25 |
26 | import biz.paluch.spinach.api.DisqueConnection;
27 | import biz.paluch.spinach.support.DefaultDisqueClient;
28 | import biz.paluch.spinach.support.FastShutdown;
29 |
30 | /**
31 | * @author Mark Paluch
32 | */
33 | public class ClusterConnectionTest {
34 |
35 | private static DisqueClient disqueClient;
36 |
37 | @BeforeClass
38 | public static void beforeClass() {
39 |
40 | DisqueURI disqueURI = new DisqueURI.Builder().withDisque(host(), port()).withDisque(host(), port(1)).build();
41 | disqueClient = DisqueClient.create(DefaultDisqueClient.getClientResources(), disqueURI);
42 | }
43 |
44 | @AfterClass
45 | public static void afterClass() {
46 | FastShutdown.shutdown(disqueClient);
47 | }
48 |
49 | @Test
50 | public void connect() throws Exception {
51 | DisqueConnection connection = disqueClient.connect();
52 |
53 | assertThat(connection.sync().info()).contains("tcp_port:" + port());
54 | connection.sync().quit();
55 | assertThat(connection.sync().info()).contains("tcp_port:" + port(1));
56 |
57 | assertThat(connection.isOpen()).isTrue();
58 |
59 | connection.close();
60 | }
61 | }
62 |
--------------------------------------------------------------------------------
/src/main/java/biz/paluch/spinach/api/async/DisqueAsyncCommands.java:
--------------------------------------------------------------------------------
1 | /*
2 | * Copyright 2016 the original author or authors.
3 | *
4 | * Licensed under the Apache License, Version 2.0 (the "License");
5 | * you may not use this file except in compliance with the License.
6 | * You may obtain a copy of the License at
7 | *
8 | * http://www.apache.org/licenses/LICENSE-2.0
9 | *
10 | * Unless required by applicable law or agreed to in writing, software
11 | * distributed under the License is distributed on an "AS IS" BASIS,
12 | * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
13 | * See the License for the specific language governing permissions and
14 | * limitations under the License.
15 | */
16 | package biz.paluch.spinach.api.async;
17 |
18 | import biz.paluch.spinach.api.DisqueConnection;
19 | import com.lambdaworks.redis.RedisFuture;
20 |
21 | /**
22 | * Asynchronous executed commands for Disque. This API is thread-safe.
23 | *
24 | * @param Key type.
25 | * @param Value type.
26 | * @author Mark Paluch
27 | */
28 | public interface DisqueAsyncCommands extends DisqueJobAsyncCommands, DisqueQueueAsyncCommands,
29 | DisqueServerAsyncCommands, DisqueClusterAsyncCommands {
30 |
31 | /**
32 | * Authenticate to the server.
33 | *
34 | * @param password the password
35 | * @return String simple-string-reply
36 | */
37 | RedisFuture auth(String password);
38 |
39 | /**
40 | * Close the connection. The connection will become not usable anymore as soon as this method was called.
41 | */
42 | void close();
43 |
44 | /**
45 | *
46 | * @return the underlying connection.
47 | */
48 | DisqueConnection getConnection();
49 |
50 | /**
51 | *
52 | * @return true if the connection is open (connected and not closed).
53 | */
54 | boolean isOpen();
55 |
56 | /**
57 | * Ping the server.
58 | *
59 | * @return simple-string-reply
60 | */
61 | RedisFuture ping();
62 |
63 | /**
64 | * Close the connection.
65 | *
66 | * @return String simple-string-reply always OK.
67 | */
68 | RedisFuture quit();
69 |
70 | }
71 |
--------------------------------------------------------------------------------
/src/test/java/biz/paluch/spinach/support/DefaultDisqueClient.java:
--------------------------------------------------------------------------------
1 | /*
2 | * Copyright 2016 the original author or authors.
3 | *
4 | * Licensed under the Apache License, Version 2.0 (the "License");
5 | * you may not use this file except in compliance with the License.
6 | * You may obtain a copy of the License at
7 | *
8 | * http://www.apache.org/licenses/LICENSE-2.0
9 | *
10 | * Unless required by applicable law or agreed to in writing, software
11 | * distributed under the License is distributed on an "AS IS" BASIS,
12 | * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
13 | * See the License for the specific language governing permissions and
14 | * limitations under the License.
15 | */
16 | package biz.paluch.spinach.support;
17 |
18 | import java.util.concurrent.TimeUnit;
19 |
20 | import biz.paluch.spinach.DisqueClient;
21 | import biz.paluch.spinach.DisqueURI;
22 | import biz.paluch.spinach.TestSettings;
23 |
24 | import com.lambdaworks.redis.resource.ClientResources;
25 |
26 | /**
27 | * @author Mark Paluch
28 | */
29 | public class DefaultDisqueClient {
30 |
31 | public final static DefaultDisqueClient instance = new DefaultDisqueClient();
32 |
33 | private DisqueClient disqueClient;
34 | private ClientResources clientResources;
35 |
36 | public DefaultDisqueClient() {
37 | clientResources = TestClientResources.create();
38 | disqueClient = DisqueClient.create(clientResources, DisqueURI.Builder.disque(TestSettings.host(), TestSettings.port())
39 | .build());
40 | Runtime.getRuntime().addShutdownHook(new Thread() {
41 | @Override
42 | public void run() {
43 | FastShutdown.shutdown(disqueClient);
44 | }
45 | });
46 | }
47 |
48 | /**
49 | * Do not close the client.
50 | *
51 | * @return the default disque client for the tests.
52 | */
53 | public static DisqueClient get() {
54 | instance.disqueClient.setDefaultTimeout(60, TimeUnit.SECONDS);
55 | return instance.disqueClient;
56 | }
57 |
58 | /**
59 | * Do not close the client resources.
60 | * @return the default client resources for the tests.
61 | */
62 | public static ClientResources getClientResources() {
63 | return instance.clientResources;
64 | }
65 | }
66 |
--------------------------------------------------------------------------------
/src/main/java/biz/paluch/spinach/api/DisqueConnection.java:
--------------------------------------------------------------------------------
1 | /*
2 | * Copyright 2016 the original author or authors.
3 | *
4 | * Licensed under the Apache License, Version 2.0 (the "License");
5 | * you may not use this file except in compliance with the License.
6 | * You may obtain a copy of the License at
7 | *
8 | * http://www.apache.org/licenses/LICENSE-2.0
9 | *
10 | * Unless required by applicable law or agreed to in writing, software
11 | * distributed under the License is distributed on an "AS IS" BASIS,
12 | * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
13 | * See the License for the specific language governing permissions and
14 | * limitations under the License.
15 | */
16 | package biz.paluch.spinach.api;
17 |
18 | import biz.paluch.spinach.api.async.DisqueAsyncCommands;
19 | import biz.paluch.spinach.api.rx.DisqueReactiveCommands;
20 | import biz.paluch.spinach.api.sync.DisqueCommands;
21 |
22 | import com.lambdaworks.redis.api.StatefulConnection;
23 |
24 | /**
25 | * A thread-safe connection to a redis server. Multiple threads may share one {@link DisqueConnection}.
26 | *
27 | * A {@link com.lambdaworks.redis.protocol.ConnectionWatchdog} monitors each connection and reconnects automatically until
28 | * {@link #close} is called. All pending commands will be (re)sent after successful reconnection.
29 | *
30 | * @param Key type.
31 | * @param Value type.
32 | * @author Mark Paluch
33 | */
34 | public interface DisqueConnection extends StatefulConnection {
35 |
36 | /**
37 | * Returns the {@link DisqueCommands} API for the current connection. Does not create a new connection.
38 | *
39 | * @return the synchronous API for the underlying connection.
40 | */
41 | DisqueCommands sync();
42 |
43 | /**
44 | * Returns the {@link DisqueAsyncCommands} API for the current connection. Does not create a new connection.
45 | *
46 | * @return the asynchronous API for the underlying connection.
47 | */
48 | DisqueAsyncCommands async();
49 |
50 | /**
51 | * Returns the {@link DisqueReactiveCommands} API for the current connection. Does not create a new connection.
52 | *
53 | * @return the reactive API for the underlying connection.
54 | */
55 | DisqueReactiveCommands reactive();
56 |
57 | }
58 |
--------------------------------------------------------------------------------
/src/test/java/biz/paluch/spinach/support/TestEventLoopGroupProvider.java:
--------------------------------------------------------------------------------
1 | /*
2 | * Copyright 2016 the original author or authors.
3 | *
4 | * Licensed under the Apache License, Version 2.0 (the "License");
5 | * you may not use this file except in compliance with the License.
6 | * You may obtain a copy of the License at
7 | *
8 | * http://www.apache.org/licenses/LICENSE-2.0
9 | *
10 | * Unless required by applicable law or agreed to in writing, software
11 | * distributed under the License is distributed on an "AS IS" BASIS,
12 | * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
13 | * See the License for the specific language governing permissions and
14 | * limitations under the License.
15 | */
16 | package biz.paluch.spinach.support;
17 |
18 | import java.util.concurrent.TimeUnit;
19 |
20 | import com.lambdaworks.redis.resource.DefaultEventLoopGroupProvider;
21 |
22 | import io.netty.util.concurrent.DefaultPromise;
23 | import io.netty.util.concurrent.EventExecutorGroup;
24 | import io.netty.util.concurrent.ImmediateEventExecutor;
25 | import io.netty.util.concurrent.Promise;
26 |
27 | /**
28 | * A {@link com.lambdaworks.redis.resource.EventLoopGroupProvider} suitable for testing. Preserves the event loop groups between
29 | * tests. Every time a new {@link TestEventLoopGroupProvider} instance is created, shutdown hook is added
30 | * {@link Runtime#addShutdownHook(Thread)}.
31 | *
32 | * @author Mark Paluch
33 | */
34 | public class TestEventLoopGroupProvider extends DefaultEventLoopGroupProvider {
35 |
36 | public TestEventLoopGroupProvider() {
37 | super(10);
38 | Runtime.getRuntime().addShutdownHook(new Thread() {
39 | @Override
40 | public void run() {
41 | try {
42 | TestEventLoopGroupProvider.this.shutdown(100, 100, TimeUnit.MILLISECONDS).get(10, TimeUnit.SECONDS);
43 | } catch (Exception e) {
44 | e.printStackTrace();
45 | }
46 | }
47 | });
48 | }
49 |
50 | @Override
51 | public Promise release(EventExecutorGroup eventLoopGroup, long quietPeriod, long timeout, TimeUnit unit) {
52 | DefaultPromise result = new DefaultPromise(ImmediateEventExecutor.INSTANCE);
53 | result.setSuccess(true);
54 |
55 | return result;
56 | }
57 | }
58 |
--------------------------------------------------------------------------------
/src/main/java/biz/paluch/spinach/api/sync/DisqueCommands.java:
--------------------------------------------------------------------------------
1 | /*
2 | * Copyright 2016 the original author or authors.
3 | *
4 | * Licensed under the Apache License, Version 2.0 (the "License");
5 | * you may not use this file except in compliance with the License.
6 | * You may obtain a copy of the License at
7 | *
8 | * http://www.apache.org/licenses/LICENSE-2.0
9 | *
10 | * Unless required by applicable law or agreed to in writing, software
11 | * distributed under the License is distributed on an "AS IS" BASIS,
12 | * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
13 | * See the License for the specific language governing permissions and
14 | * limitations under the License.
15 | */
16 | package biz.paluch.spinach.api.sync;
17 |
18 | import java.util.concurrent.TimeUnit;
19 |
20 | import biz.paluch.spinach.api.DisqueConnection;
21 |
22 | /**
23 | *
24 | * Synchronous executed commands for Disque. This API is thread-safe.
25 | *
26 | * @param Key type.
27 | * @param Value type.
28 | * @author Mark Paluch
29 | */
30 | public interface DisqueCommands extends DisqueJobCommands, DisqueQueueCommands, DisqueServerCommands,
31 | DisqueClusterCommands {
32 |
33 | /**
34 | * Authenticate to the server.
35 | *
36 | * @param password the password
37 | * @return String simple-string-reply
38 | */
39 | String auth(String password);
40 |
41 | /**
42 | * Close the connection. The connection will become not usable anymore as soon as this method was called.
43 | */
44 | void close();
45 |
46 | /**
47 | *
48 | * @return the underlying connection.
49 | */
50 | DisqueConnection getConnection();
51 |
52 | /**
53 | *
54 | * @return true if the connection is open (connected and not closed).
55 | */
56 | boolean isOpen();
57 |
58 | /**
59 | * Ping the server.
60 | *
61 | * @return simple-string-reply
62 | */
63 | String ping();
64 |
65 | /**
66 | * Close the connection.
67 | *
68 | * @return String simple-string-reply always OK.
69 | */
70 | String quit();
71 |
72 | /**
73 | * Set the default timeout for operations.
74 | *
75 | * @param timeout the timeout value
76 | * @param unit the unit of the timeout value
77 | */
78 | void setTimeout(long timeout, TimeUnit unit);
79 | }
80 |
--------------------------------------------------------------------------------
/src/main/java/biz/paluch/spinach/output/JobOutput.java:
--------------------------------------------------------------------------------
1 | /*
2 | * Copyright 2016 the original author or authors.
3 | *
4 | * Licensed under the Apache License, Version 2.0 (the "License");
5 | * you may not use this file except in compliance with the License.
6 | * You may obtain a copy of the License at
7 | *
8 | * http://www.apache.org/licenses/LICENSE-2.0
9 | *
10 | * Unless required by applicable law or agreed to in writing, software
11 | * distributed under the License is distributed on an "AS IS" BASIS,
12 | * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
13 | * See the License for the specific language governing permissions and
14 | * limitations under the License.
15 | */
16 | package biz.paluch.spinach.output;
17 |
18 | import java.nio.ByteBuffer;
19 | import java.util.HashMap;
20 | import java.util.Map;
21 |
22 | import biz.paluch.spinach.api.Job;
23 |
24 | import com.lambdaworks.redis.codec.RedisCodec;
25 | import com.lambdaworks.redis.output.CommandOutput;
26 |
27 | /**
28 | * Output handler for commands returning {@link Job} data structres.
29 | *
30 | * @author Mark Paluch
31 | */
32 | public class JobOutput extends CommandOutput> {
33 |
34 | private K queue;
35 | private String id;
36 | private V body;
37 | private Map counters = new HashMap();
38 | private String lastKey;
39 |
40 | public JobOutput(RedisCodec codec) {
41 | super(codec, null);
42 | }
43 |
44 | @Override
45 | public void set(ByteBuffer bytes) {
46 |
47 | if (queue == null) {
48 | queue = codec.decodeKey(bytes);
49 | return;
50 | }
51 |
52 | if (id == null) {
53 | id = decodeAscii(bytes);
54 | return;
55 | }
56 |
57 | if (body == null) {
58 | counters = new HashMap();
59 | body = codec.decodeValue(bytes);
60 | return;
61 | }
62 |
63 | lastKey = decodeAscii(bytes);
64 | }
65 |
66 | @Override
67 | public void set(long integer) {
68 | if (lastKey != null) {
69 | counters.put(lastKey, integer);
70 | lastKey = null;
71 | }
72 | }
73 |
74 | @Override
75 | public void complete(int depth) {
76 | if (queue != null && id != null && body != null && counters != null) {
77 | output = new Job(queue, id, body, counters);
78 | }
79 | }
80 | }
81 |
--------------------------------------------------------------------------------
/src/test/java/biz/paluch/spinach/commands/rx/RxJobCommandTest.java:
--------------------------------------------------------------------------------
1 | /*
2 | * Copyright 2016 the original author or authors.
3 | *
4 | * Licensed under the Apache License, Version 2.0 (the "License");
5 | * you may not use this file except in compliance with the License.
6 | * You may obtain a copy of the License at
7 | *
8 | * http://www.apache.org/licenses/LICENSE-2.0
9 | *
10 | * Unless required by applicable law or agreed to in writing, software
11 | * distributed under the License is distributed on an "AS IS" BASIS,
12 | * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
13 | * See the License for the specific language governing permissions and
14 | * limitations under the License.
15 | */
16 | package biz.paluch.spinach.commands.rx;
17 |
18 | import static org.assertj.core.api.Assertions.assertThat;
19 |
20 | import java.util.concurrent.TimeUnit;
21 |
22 | import org.junit.Before;
23 | import org.junit.Test;
24 |
25 | import rx.Observable;
26 | import rx.functions.Func1;
27 | import biz.paluch.spinach.api.Job;
28 | import biz.paluch.spinach.api.rx.DisqueReactiveCommands;
29 | import biz.paluch.spinach.commands.JobCommandTest;
30 |
31 | /**
32 | * @author Mark Paluch
33 | */
34 | public class RxJobCommandTest extends JobCommandTest {
35 |
36 | protected DisqueReactiveCommands rx;
37 |
38 | @Before
39 | public void openConnection() throws Exception {
40 | disque = RxSyncInvocationHandler.sync(client.connect());
41 | disque.debugFlushall();
42 | rx = disque.getConnection().reactive();
43 | }
44 |
45 | @Test
46 | public void addJob() throws Exception {
47 |
48 | String result = rx.addjob(queue, value, 5, TimeUnit.SECONDS).toBlocking().first();
49 | assertThat(result).startsWith("D-");
50 | }
51 |
52 | @Test
53 | public void rxChaining() throws Exception {
54 |
55 | addJob();
56 | long qlen = rx.qlen(queue).toBlocking().first();
57 |
58 | assertThat(qlen).isEqualTo(1);
59 |
60 | final DisqueReactiveCommands rx = client.connect().reactive();
61 | rx.getjob(queue).flatMap(new Func1, Observable>() {
62 | @Override
63 | public Observable call(Job job) {
64 | return rx.ackjob(job.getId());
65 | }
66 | }).subscribe();
67 |
68 | assertThat(rx.qlen(queue).toBlocking().first()).isEqualTo(0);
69 |
70 | }
71 |
72 | }
73 |
--------------------------------------------------------------------------------
/src/assembly/bin.xml:
--------------------------------------------------------------------------------
1 |
4 | bin
5 |
6 | tar.gz
7 | zip
8 | dir
9 |
10 | ${project.artifactId}-${project.version}-bin
11 | false
12 |
13 |
14 |
15 | biz.paluch.redis:spinach:jar:${project.version}
16 |
17 |
18 | false
19 | true
20 | true
21 |
22 |
23 |
24 | io.netty:*
25 |
26 | provided
27 | dependencies
28 | false
29 |
30 |
31 |
32 | io.netty:*
33 | io.reactivex:*
34 | com.google.guava:*
35 | org.apache.commons:*
36 | biz.paluch.redis:lettuce:*
37 |
38 | dependencies
39 | false
40 |
41 |
42 |
43 | biz.paluch.redis:spinach:*:javadoc
44 |
45 | apidocs
46 | true
47 | false
48 | true
49 |
50 |
51 |
52 |
53 |
54 |
55 | LICENSE
56 | README.md
57 | RELEASE-NOTES.md
58 |
59 |
60 |
61 |
62 |
--------------------------------------------------------------------------------
/src/site/site.xml:
--------------------------------------------------------------------------------
1 |
16 |
19 |
20 | spinach - A scalable Java Disque client
21 | http://oss.paluch.biz/spinach-doc
22 |
23 |
24 |
25 |
32 |
33 |
36 |
37 |
38 |
39 |
40 |
41 |
42 | true
43 |
44 | mp911de/spinach
45 | right
46 | black
47 |
48 |
49 | mp911de
50 | true
51 | true
52 |
53 |
54 | piwik.paluch.biz
55 | 8
56 |
57 |
58 |
59 |
60 |
61 | org.apache.maven.skins
62 | maven-fluido-skin
63 | 1.3.1
64 |
65 |
--------------------------------------------------------------------------------
/src/test/java/biz/paluch/spinach/RoundRobinSocketAddressSupplierTest.java:
--------------------------------------------------------------------------------
1 | /*
2 | * Copyright 2016 the original author or authors.
3 | *
4 | * Licensed under the Apache License, Version 2.0 (the "License");
5 | * you may not use this file except in compliance with the License.
6 | * You may obtain a copy of the License at
7 | *
8 | * http://www.apache.org/licenses/LICENSE-2.0
9 | *
10 | * Unless required by applicable law or agreed to in writing, software
11 | * distributed under the License is distributed on an "AS IS" BASIS,
12 | * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
13 | * See the License for the specific language governing permissions and
14 | * limitations under the License.
15 | */
16 | package biz.paluch.spinach;
17 |
18 | import static org.assertj.core.api.Assertions.assertThat;
19 |
20 | import java.net.InetSocketAddress;
21 | import java.util.Arrays;
22 | import java.util.Collection;
23 |
24 | import org.junit.Test;
25 |
26 | import biz.paluch.spinach.impl.RoundRobinSocketAddressSupplier;
27 |
28 | /**
29 | * @author Mark Paluch
30 | */
31 | public class RoundRobinSocketAddressSupplierTest {
32 |
33 | private static DisqueURI.DisqueHostAndPort hap1 = new DisqueURI.DisqueHostAndPort("127.0.0.1", 1);
34 | private static DisqueURI.DisqueHostAndPort hap2 = new DisqueURI.DisqueHostAndPort("127.0.0.1", 2);
35 | private static DisqueURI.DisqueHostAndPort hap3 = new DisqueURI.DisqueHostAndPort("127.0.0.1", 3);
36 |
37 | private Collection points = Arrays.asList(hap1, hap2, hap3);
38 |
39 | @Test
40 | public void noOffset() throws Exception {
41 |
42 | RoundRobinSocketAddressSupplier sut = new RoundRobinSocketAddressSupplier(points, null);
43 |
44 | assertThat(sut.get()).isEqualTo(getSocketAddress(hap1));
45 | assertThat(sut.get()).isEqualTo(getSocketAddress(hap2));
46 | assertThat(sut.get()).isEqualTo(getSocketAddress(hap3));
47 | assertThat(sut.get()).isEqualTo(getSocketAddress(hap1));
48 | }
49 |
50 | @Test
51 | public void withOffset() throws Exception {
52 |
53 | RoundRobinSocketAddressSupplier sut = new RoundRobinSocketAddressSupplier(points, hap2);
54 |
55 | assertThat(sut.get()).isEqualTo(getSocketAddress(hap3));
56 | assertThat(sut.get()).isEqualTo(getSocketAddress(hap1));
57 | assertThat(sut.get()).isEqualTo(getSocketAddress(hap2));
58 | assertThat(sut.get()).isEqualTo(getSocketAddress(hap3));
59 | }
60 |
61 | private InetSocketAddress getSocketAddress(DisqueURI.DisqueHostAndPort hostAndPort) {
62 | return InetSocketAddress.createUnresolved(hostAndPort.getHost(), hostAndPort
63 | .getPort());
64 | }
65 | }
--------------------------------------------------------------------------------
/src/main/java/biz/paluch/spinach/impl/HelloClusterSocketAddressSupplier.java:
--------------------------------------------------------------------------------
1 | /*
2 | * Copyright 2016 the original author or authors.
3 | *
4 | * Licensed under the Apache License, Version 2.0 (the "License");
5 | * you may not use this file except in compliance with the License.
6 | * You may obtain a copy of the License at
7 | *
8 | * http://www.apache.org/licenses/LICENSE-2.0
9 | *
10 | * Unless required by applicable law or agreed to in writing, software
11 | * distributed under the License is distributed on an "AS IS" BASIS,
12 | * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
13 | * See the License for the specific language governing permissions and
14 | * limitations under the License.
15 | */
16 | package biz.paluch.spinach.impl;
17 |
18 | import java.net.InetSocketAddress;
19 | import java.net.SocketAddress;
20 |
21 | import biz.paluch.spinach.api.DisqueConnection;
22 | import biz.paluch.spinach.cluster.DisqueNode;
23 |
24 | /**
25 | * Supplier for {@link SocketAddress adresses} that is aware of the cluster nodes.
26 | *
27 | * This class performs a {@code HELLO} command handshake upon connection and retrieves the nodes from the command result. The
28 | * node set is not refreshed once it is retrieved. The nodes are used in the order of their priority in a round-robin fashion.
29 | * Until the handshake is completed a fallback {@link SocketAddressSupplier} is used.
30 | *
31 | *
32 | * @author Mark Paluch
33 | */
34 | public class HelloClusterSocketAddressSupplier extends ClusterAwareNodeSupport implements SocketAddressSupplier,
35 | ConnectionAware {
36 |
37 | protected final SocketAddressSupplier bootstrap;
38 | protected RoundRobin roundRobin;
39 |
40 | /**
41 | *
42 | * @param bootstrap bootstrap/fallback {@link SocketAddressSupplier} for bootstrapping before any communication is done.
43 | */
44 | public HelloClusterSocketAddressSupplier(SocketAddressSupplier bootstrap) {
45 | this.bootstrap = bootstrap;
46 | }
47 |
48 | @Override
49 | public SocketAddress get() {
50 |
51 | if (getNodes().isEmpty()) {
52 | return bootstrap.get();
53 | }
54 |
55 | DisqueNode disqueNode = roundRobin.next();
56 | return InetSocketAddress.createUnresolved(disqueNode.getAddr(), disqueNode.getPort());
57 | }
58 |
59 | @Override
60 | public void setConnection(DisqueConnection disqueConnection) {
61 | super.setConnection(disqueConnection);
62 | reloadNodes();
63 | }
64 |
65 | @Override
66 | public void reloadNodes() {
67 | super.reloadNodes();
68 | roundRobin = new RoundRobin(getNodes());
69 | }
70 |
71 | }
72 |
--------------------------------------------------------------------------------
/src/test/java/biz/paluch/spinach/UnixDomainSocketTest.java:
--------------------------------------------------------------------------------
1 | /*
2 | * Copyright 2016 the original author or authors.
3 | *
4 | * Licensed under the Apache License, Version 2.0 (the "License");
5 | * you may not use this file except in compliance with the License.
6 | * You may obtain a copy of the License at
7 | *
8 | * http://www.apache.org/licenses/LICENSE-2.0
9 | *
10 | * Unless required by applicable law or agreed to in writing, software
11 | * distributed under the License is distributed on an "AS IS" BASIS,
12 | * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
13 | * See the License for the specific language governing permissions and
14 | * limitations under the License.
15 | */
16 | package biz.paluch.spinach;
17 |
18 | import static org.assertj.core.api.Assertions.assertThat;
19 | import static org.junit.Assume.assumeTrue;
20 |
21 | import java.util.Locale;
22 |
23 | import biz.paluch.spinach.support.DefaultDisqueClient;
24 | import org.junit.Test;
25 |
26 | import biz.paluch.spinach.api.sync.DisqueCommands;
27 | import biz.paluch.spinach.commands.AbstractCommandTest;
28 | import biz.paluch.spinach.support.FastShutdown;
29 |
30 | import com.lambdaworks.redis.resource.ClientResources;
31 | import io.netty.util.internal.SystemPropertyUtil;
32 |
33 | /**
34 | * @author Mark Paluch
35 | */
36 | public class UnixDomainSocketTest extends AbstractCommandTest {
37 |
38 | private static ClientResources clientResources = DefaultDisqueClient.getClientResources();
39 |
40 | @Test
41 | public void linux_x86_64_socket() throws Exception {
42 |
43 | linuxOnly();
44 |
45 | DisqueClient disqueClient = DisqueClient.create(clientResources, DisqueURI.Builder.disqueSocket(TestSettings.socket())
46 | .build());
47 |
48 | DisqueCommands connection = disqueClient.connect().sync();
49 |
50 | connection.debugFlushall();
51 | connection.ping();
52 |
53 | FastShutdown.shutdown(disqueClient);
54 | }
55 |
56 | @Test
57 | public void differentSocketTypes() throws Exception {
58 |
59 | DisqueClient disqueClient = DisqueClient.create(clientResources, DisqueURI.Builder.disqueSocket(TestSettings.socket())
60 | .withDisque(TestSettings.host()).build());
61 |
62 | try {
63 | disqueClient.connect();
64 | } catch (Exception e) {
65 | assertThat(e).hasMessageContaining("You cannot mix unix");
66 | }
67 |
68 | FastShutdown.shutdown(disqueClient);
69 | }
70 |
71 | private void linuxOnly() {
72 | String osName = SystemPropertyUtil.get("os.name").toLowerCase(Locale.UK).trim();
73 | assumeTrue("Only supported on Linux, your os is " + osName, osName.startsWith("linux"));
74 | }
75 |
76 | }
77 |
--------------------------------------------------------------------------------
/src/main/java/biz/paluch/spinach/output/QstatMapOutput.java:
--------------------------------------------------------------------------------
1 | /*
2 | * Copyright 2016 the original author or authors.
3 | *
4 | * Licensed under the Apache License, Version 2.0 (the "License");
5 | * you may not use this file except in compliance with the License.
6 | * You may obtain a copy of the License at
7 | *
8 | * http://www.apache.org/licenses/LICENSE-2.0
9 | *
10 | * Unless required by applicable law or agreed to in writing, software
11 | * distributed under the License is distributed on an "AS IS" BASIS,
12 | * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
13 | * See the License for the specific language governing permissions and
14 | * limitations under the License.
15 | */
16 | package biz.paluch.spinach.output;
17 |
18 | import java.nio.ByteBuffer;
19 | import java.util.*;
20 |
21 | import com.lambdaworks.redis.codec.RedisCodec;
22 | import com.lambdaworks.redis.output.CommandOutput;
23 |
24 | /**
25 | * @author Mark Paluch
26 | */
27 | public class QstatMapOutput extends CommandOutput> {
28 | private final Deque> stack;
29 | private int depth;
30 | private String key;
31 |
32 | @SuppressWarnings("rawtypes")
33 | public QstatMapOutput(RedisCodec codec) {
34 | super(codec, new HashMap());
35 | stack = new LinkedList>();
36 | depth = 0;
37 | }
38 |
39 | @Override
40 | public void set(ByteBuffer bytes) {
41 | if (stack.isEmpty()) {
42 | if (key == null) {
43 | key = decodeAscii(bytes);
44 | return;
45 | }
46 |
47 | Object value = (bytes == null) ? null : key.equals("queue") ? codec.decodeKey(bytes) : decodeAscii(bytes);
48 | output.put(key, value);
49 | key = null;
50 | } else {
51 | stack.peek().add(bytes == null ? null : decodeAscii(bytes));
52 | }
53 | }
54 |
55 | @Override
56 | public void set(long integer) {
57 | if (stack.isEmpty()) {
58 | if (key == null) {
59 | key = "";
60 | return;
61 | }
62 |
63 | output.put(key, Long.valueOf(integer));
64 | key = null;
65 | } else {
66 | stack.peek().add(integer);
67 | }
68 | }
69 |
70 | @Override
71 | public void complete(int depth) {
72 | if (depth < this.depth) {
73 | if (!stack.isEmpty()) {
74 | output.put(key, stack.pop());
75 | key = null;
76 | }
77 | this.depth--;
78 | }
79 | }
80 |
81 | @Override
82 | public void multi(int count) {
83 | this.depth++;
84 | if (depth > 1) {
85 | List