1
1
package com .redislabs .riot ;
2
2
3
+ import java .net .InetAddress ;
4
+ import java .text .NumberFormat ;
3
5
import java .util .List ;
4
6
import java .util .Locale ;
5
7
8
+ import org .springframework .batch .core .ExitStatus ;
9
+ import org .springframework .batch .core .Job ;
10
+ import org .springframework .batch .core .JobExecution ;
11
+ import org .springframework .batch .core .JobParameters ;
12
+ import org .springframework .batch .core .configuration .annotation .JobBuilderFactory ;
13
+ import org .springframework .batch .core .configuration .annotation .StepBuilderFactory ;
14
+ import org .springframework .batch .core .launch .support .SimpleJobLauncher ;
15
+ import org .springframework .batch .core .repository .JobRepository ;
16
+ import org .springframework .batch .core .repository .support .MapJobRepositoryFactoryBean ;
17
+ import org .springframework .batch .item .ItemProcessor ;
18
+ import org .springframework .batch .item .ItemStreamWriter ;
19
+ import org .springframework .batch .item .support .AbstractItemCountingItemStreamItemReader ;
20
+ import org .springframework .batch .support .transaction .ResourcelessTransactionManager ;
6
21
import org .springframework .boot .CommandLineRunner ;
7
22
import org .springframework .boot .SpringApplication ;
8
23
import org .springframework .boot .autoconfigure .SpringBootApplication ;
24
+ import org .springframework .core .task .SyncTaskExecutor ;
25
+ import org .springframework .transaction .PlatformTransactionManager ;
9
26
27
+ import com .redislabs .riot .batch .JobBuilder ;
10
28
import com .redislabs .riot .cli .BaseCommand ;
11
- import com .redislabs .riot .cli .in .ImportCommand ;
29
+ import com .redislabs .riot .cli .ImportCommand ;
30
+ import com .redislabs .riot .redis .RedisConnectionBuilder ;
12
31
32
+ import io .lettuce .core .RedisURI ;
33
+ import lombok .Getter ;
13
34
import picocli .CommandLine ;
14
35
import picocli .CommandLine .Command ;
15
36
import picocli .CommandLine .DefaultExceptionHandler ;
37
+ import picocli .CommandLine .HelpCommand ;
16
38
import picocli .CommandLine .Option ;
17
39
import picocli .CommandLine .RunLast ;
40
+ import redis .clients .jedis .Protocol ;
18
41
19
42
@ SpringBootApplication
20
- @ Command (name = "riot" , subcommands = { ImportCommand .class })
43
+ @ Command (name = "riot" , subcommands = { HelpCommand . class , ImportCommand .class })
21
44
public class RiotApplication extends BaseCommand implements CommandLineRunner {
22
45
46
+ public static final String DEFAULT_HOST = "localhost" ;
47
+
48
+ public enum RedisDriver {
49
+ Jedis , Lettuce
50
+ }
51
+
23
52
/**
24
53
* Just to avoid picocli complain in Eclipse console
25
54
*/
26
55
@ Option (names = "--spring.output.ansi.enabled" , hidden = true )
27
56
private String ansiEnabled ;
57
+ @ Option (names = "--max" , description = "Maximum number of items to read." , paramLabel = "<count>" )
58
+ private Integer maxCount ;
59
+ @ Option (names = "--threads" , description = "Number of partitions to use for processing. (default: ${DEFAULT-VALUE})." )
60
+ private int threads = 1 ;
61
+ @ Option (names = "--chunk-size" , description = "The chunk size commit interval. (default: ${DEFAULT-VALUE})." )
62
+ private int chunkSize = JobBuilder .DEFAULT_CHUNK_SIZE ;
63
+ @ Option (names = "--sleep" , description = "Sleep duration in milliseconds between each read." )
64
+ private Long sleep ;
65
+ @ Option (names = "--host" , description = "Redis server host. (default: localhost)." )
66
+ private InetAddress host ;
67
+ @ Getter
68
+ @ Option (names = "--port" , description = "Redis server port. (default: ${DEFAULT-VALUE})." )
69
+ private int port = RedisURI .DEFAULT_REDIS_PORT ;
70
+ @ Option (names = "--command-timeout" , description = "Redis command timeout in seconds for synchronous command execution (default: ${DEFAULT-VALUE})." )
71
+ private long commandTimeout = RedisURI .DEFAULT_TIMEOUT ;
72
+ @ Getter
73
+ @ Option (names = "--connection-timeout" , description = "Redis connect timeout in milliseconds. (default: ${DEFAULT-VALUE})." )
74
+ private int connectionTimeout = Protocol .DEFAULT_TIMEOUT ;
75
+ @ Option (names = "--socket-timeout" , description = "Redis socket timeout in milliseconds. (default: ${DEFAULT-VALUE})." )
76
+ private int socketTimeout = Protocol .DEFAULT_TIMEOUT ;
77
+ @ Getter
78
+ @ Option (names = "--password" , description = "Redis database password." , interactive = true )
79
+ protected String password ;
80
+ @ Option (names = "--max-idle" , description = "Maximum number of idle connections in the pool. Use a negative value to indicate an unlimited number of idle connections. (default: ${DEFAULT-VALUE})." )
81
+ private int maxIdle = 8 ;
82
+ @ Option (names = "--min-idle" , description = "Target for the minimum number of idle connections to maintain in the pool. This setting only has an effect if it is positive. (default: ${DEFAULT-VALUE})." )
83
+ private int minIdle = 0 ;
84
+ @ Getter
85
+ @ Option (names = "--max-total" , description = "Maximum number of connections that can be allocated by the pool at a given time. Use a negative value for no limit. (default: ${DEFAULT-VALUE})" )
86
+ private int maxTotal = 8 ;
87
+ @ Option (names = "--max-wait" , description = "Maximum amount of time in milliseconds a connection allocation should block before throwing an exception when the pool is exhausted. Use a negative value to block indefinitely (default)." )
88
+ private long maxWait = -1L ;
89
+ @ Option (names = "--database" , description = "Redis database number. Databases are only available for Redis Standalone and Redis Master/Slave. (default: ${DEFAULT-VALUE})." )
90
+ private int database = 0 ;
91
+ @ Option (names = "--client-name" , description = "Redis client name." )
92
+ private String clientName ;
93
+ @ Getter
94
+ @ Option (names = "--driver" , description = "Redis driver: ${COMPLETION-CANDIDATES}. (default: ${DEFAULT-VALUE})" )
95
+ private RedisDriver driver = RedisDriver .Jedis ;
28
96
29
97
public static void main (String [] args ) {
30
98
SpringApplication .run (RiotApplication .class , args );
@@ -42,9 +110,69 @@ public void run(String... args) {
42
110
commandLine .parseWithHandlers (handler , exceptionHandler , args );
43
111
}
44
112
45
- @ Override
46
- public void run () {
47
- CommandLine .usage (this , System .out );
113
+ public RedisConnectionBuilder redisConnectionBuilder () {
114
+ RedisConnectionBuilder builder = new RedisConnectionBuilder ();
115
+ builder .setClientName (clientName );
116
+ builder .setCommandTimeout (commandTimeout );
117
+ builder .setConnectionTimeout (connectionTimeout );
118
+ builder .setDatabase (database );
119
+ builder .setHost (getHostname ());
120
+ builder .setMaxTotal (maxTotal );
121
+ builder .setMaxIdle (maxIdle );
122
+ builder .setMaxWait (maxWait );
123
+ builder .setMinIdle (minIdle );
124
+ builder .setPassword (password );
125
+ builder .setPort (port );
126
+ builder .setSocketTimeout (socketTimeout );
127
+ return builder ;
128
+ }
129
+
130
+ public String getHostname () {
131
+ if (host != null ) {
132
+ return host .getHostName ();
133
+ }
134
+ return DEFAULT_HOST ;
135
+ }
136
+
137
+ public <I , O > ExitStatus call (AbstractItemCountingItemStreamItemReader <I > reader , ItemProcessor <I , O > processor ,
138
+ ItemStreamWriter <O > writer ) throws Exception {
139
+ PlatformTransactionManager transactionManager = new ResourcelessTransactionManager ();
140
+ MapJobRepositoryFactoryBean jobRepositoryFactory = new MapJobRepositoryFactoryBean (transactionManager );
141
+ jobRepositoryFactory .afterPropertiesSet ();
142
+ JobRepository jobRepository = jobRepositoryFactory .getObject ();
143
+ JobBuilderFactory jobBuilderFactory = new JobBuilderFactory (jobRepository );
144
+ StepBuilderFactory stepBuilderFactory = new StepBuilderFactory (jobRepository , transactionManager );
145
+ JobBuilder <I , O > builder = new JobBuilder <>(jobBuilderFactory , stepBuilderFactory );
146
+ builder .setChunkSize (chunkSize );
147
+ if (maxCount != null ) {
148
+ reader .setMaxItemCount (maxCount );
149
+ }
150
+ builder .setReader (reader );
151
+ builder .setProcessor (processor );
152
+ builder .setWriter (writer );
153
+ builder .setPartitions (threads );
154
+ builder .setSleep (sleep );
155
+ Job job = builder .build ();
156
+ SimpleJobLauncher jobLauncher = new SimpleJobLauncher ();
157
+ jobLauncher .setJobRepository (jobRepository );
158
+ jobLauncher .setTaskExecutor (new SyncTaskExecutor ());
159
+ jobLauncher .afterPropertiesSet ();
160
+ long startTime = System .currentTimeMillis ();
161
+ System .out .println ("Running job" );
162
+ JobExecution execution = jobLauncher .run (job , new JobParameters ());
163
+ if (execution .getExitStatus ().equals (ExitStatus .FAILED )) {
164
+ execution .getAllFailureExceptions ().forEach (e -> e .printStackTrace ());
165
+ } else if (execution .getExitStatus ().equals (ExitStatus .COMPLETED )) {
166
+ long endTime = System .currentTimeMillis ();
167
+ long duration = endTime - startTime ;
168
+ NumberFormat numberFormat = NumberFormat .getIntegerInstance ();
169
+ double durationInSeconds = (double ) duration / 1000 ;
170
+ int writeCount = execution .getStepExecutions ().iterator ().next ().getWriteCount ();
171
+ double throughput = writeCount / durationInSeconds ;
172
+ System .out .println ("Processed " + numberFormat .format (writeCount ) + " items in " + durationInSeconds
173
+ + " seconds (" + numberFormat .format (throughput ) + " writes/sec)" );
174
+ }
175
+ return execution .getExitStatus ();
48
176
}
49
177
50
178
}
0 commit comments