This is an automated email from the ASF dual-hosted git repository.
shirshanka pushed a commit to branch master
in repository https://gitbox.apache.org/repos/asf/incubator-gobblin.git
The following commit(s) were added to refs/heads/master by this push:
new 06b9159 [GOBBLIN-1267] Gobblin cli: Add a quickApp called oneShot to
run a single command in standalone and MR mode
06b9159 is described below
commit 06b9159e034ca2a7e1b72b1a306ae24a2fe6485e
Author: Shirshanka Das <[email protected]>
AuthorDate: Mon Sep 21 23:06:42 2020 -0700
[GOBBLIN-1267] Gobblin cli: Add a quickApp called oneShot to run a single
command in standalone and MR mode
Closes #3058 from shirshanka/cli-improve
---
bin/gobblin.sh | 8 +-
gobblin-docs/user-guide/Gobblin-CLI.md | 41 ++++++++-
.../gobblin/example/generic/OneShotRunner.java | 99 ++++++++++++++++++++++
.../apache/gobblin/example/TestOneShotRunner.java | 43 ++++++++++
gobblin-example/src/test/resources/appConf.conf | 1 +
gobblin-example/src/test/resources/baseConf.conf | 2 +
.../gobblin/runtime/embedded/EmbeddedGobblin.java | 28 +++---
.../runtime/mapreduce/CliMRJobLauncher.java | 8 +-
.../gobblin/runtime/mapreduce/MRJobLauncher.java | 6 ++
.../org/apache/gobblin/runtime/cli/GobblinCli.java | 5 +-
10 files changed, 222 insertions(+), 19 deletions(-)
diff --git a/bin/gobblin.sh b/bin/gobblin.sh
index 968106a..83af03e 100755
--- a/bin/gobblin.sh
+++ b/bin/gobblin.sh
@@ -398,12 +398,13 @@ function start() {
echo "$GOBBLIN_CLASSPATH"
else
#prints the command
+ GOBBLIN_COMMAND="$JAVA_HOME/bin/java $GC_OPTS $JVM_OPTS
$LOG4J_OPTS -cp $GOBBLIN_CLASSPATH $CLI_CLASS $CMD_PARAMS"
if [[ $VERBOSE -eq 1 ]]; then
- echo "Running command: $JAVA_HOME/bin/java $GC_OPTS $JVM_OPTS
-cp $GOBBLIN_CLASSPATH $CLI_CLASS $CMD_PARAMS";
+ echo "Running command: $GOBBLIN_COMMAND";
fi
# execute the command
- $JAVA_HOME/bin/java $GC_OPTS $JVM_OPTS -cp $GOBBLIN_CLASSPATH
$CLI_CLASS $CMD_PARAMS
+ $GOBBLIN_COMMAND
fi
# for all gobblin execution modes
else
@@ -429,7 +430,8 @@ function start() {
GOBBLIN_COMMAND="hadoop jar
$GOBBLIN_LIB/gobblin-runtime-$GOBBLIN_VERSION.jar $MAPREDUCE_CLASS \
-D mapreduce.job.user.classpath.first=true $JT_COMMAND $FS_COMMAND
\
- -libjars $MR_MODE_LIB_JARS -sysconfig
$GOBBLIN_CONF/application.conf -jobconfig $JOB_CONF_FILE"
+ -libjars $MR_MODE_LIB_JARS -sysconfig
$GOBBLIN_CONF/application.conf -jobconfig $JOB_CONF_FILE \
+ $LOG4J_OPTS"
else
CLASS_N_ARGS=''
diff --git a/gobblin-docs/user-guide/Gobblin-CLI.md
b/gobblin-docs/user-guide/Gobblin-CLI.md
index d3a434a..9024ef6 100644
--- a/gobblin-docs/user-guide/Gobblin-CLI.md
+++ b/gobblin-docs/user-guide/Gobblin-CLI.md
@@ -54,7 +54,7 @@ Argument details:
* `--jvmopts`: to specify any JVM parameters, default is `-Xmx1g -Xms512m`.
* `--enable-gc-logs`: adds GC options to JVM parameters: ```
-XX:+UseConcMarkSweepGC -XX:+UseParNewGC -XX:+UseCompressedOops
-XX:+PrintGCDetails -XX:+PrintGCDateStamps -XX:+PrintTenuringDistribution
-XX:+HeapDumpOnOutOfMemoryError -XX:HeapDumpPath=$GOBBLIN_LOGS/
-Xloggc:$GOBBLIN_LOGS/gobblin-$GOBBLIN_MODE-gc.log ```
* `--show-classpath`: It prints the full value of the classpath that gobblin
uses.
-* all other arguments are sell-explanatory.
+* all other arguments are self-explanatory.
Gobblin Commands
-------------------
@@ -96,6 +96,9 @@ will provide with a list of available quick apps. To run a
quick app:
Quick apps may require additional arguments. For the usage of a particular
app, run `bin/gobblin cli run <quick-app-name> -h`.
+The Distcp Quick App
+--------------------
+
For example, consider the quick app distcp:
```bash
$ gobblin cli run distcp -h
@@ -121,6 +124,42 @@ This provides usage for the app distcp, as well as listing
all available options
gobblin cli run distcp file:///source/path file:///target/path
```
+The OneShot Quick App
+----------------------
+
+The Gobblin cli also ships with a generic job runner, the **oneShot** quick
app. You can use it to run a single job using a standard config file. This is
very useful during development, testing and also makes it easy to integrate
with schedulers that just need to fire off a command line job. The **oneShot**
app allows you to run a job in standalone mode or in map-reduce mode.
+```bash
+$ gobblin cli run oneShot -baseConf <base-config-file> -appConf
<path-to-job-conf-file>
+# The Base Config file is an optional parameter and contains defaults for your
mode of
+# execution (e.g. standalone modes would typically use
+# gobblin-dist/conf/standalone/application.conf and
+# mapreduce mode would typically use
gobblin-dist/conf/mapreduce/application.conf)
+#
+# The Job Config file is your regular .pull or .conf file and is a required
parameter.
+# You should use a fully qualified URI to your pull file. Otherwise Gobblin
will pick the
+# default FS configured in the environment, which may not be what you want.
+# e.g file:///gobblin-conf/my-job/wikipedia.pull or
hdfs:///gobblin-conf/my-job/kafka-hdfs.pull
+```
+
+The **oneShot** app comes with certain hardcoded defaults (that it inherits
from EmbeddedGobblin
[here](https://github.com/apache/incubator-gobblin/blob/master/gobblin-runtime/src/main/resources/embedded/embedded.conf)),
that you may not be expecting. Make sure you understand what they do and
override them in your baseConf or appConf files if needed.
+
+Notable differences at the time of this writing include:
+
+* state.store.enabled = false (set this to true in your appConfig or
baseConfig if you want state storage for repeated oneshot runs)
+* data.publisher.appendExtractToFinalDir = false (set this to true in your
appConfig or baseConfig if you want to see the extract name appended to the job
output directory)
+
+The **oneShot** app allows for specifying the log4j file of your job execution
which can be very helpful while debugging pesky failures.
+You can launch the job in MR-Mode by using the -mrMode switch.
+
+* oneShot execution of standalone with a log4j file.
+```bash
+$ gobblin cli run oneShot -baseConf
/app/gobblin-dist/conf/standalone/application.conf -appConf
file:///app/kafkaConfDir/kafka-simple-hdfs.pull --log4j-conf
/app/gobblin-dist/conf/standalone/log4j.properties
+```
+* oneShot execution of map-reduce job with a log4j file
+```bash
+$ gobblin cli run oneShot -mrMode -baseConf
/app/gobblin-dist/conf/standalone/application.conf -appConf
file:///app/kafkaConfDir/kafka-simple-hdfs.pull --log4j-conf
/app/gobblin-dist/conf/standalone/log4j.properties
+```
+
Developing quick apps for the CLI
--------------------------------------------
diff --git
a/gobblin-example/src/main/java/org/apache/gobblin/example/generic/OneShotRunner.java
b/gobblin-example/src/main/java/org/apache/gobblin/example/generic/OneShotRunner.java
new file mode 100644
index 0000000..501928c
--- /dev/null
+++
b/gobblin-example/src/main/java/org/apache/gobblin/example/generic/OneShotRunner.java
@@ -0,0 +1,99 @@
+/*
+ * Licensed to the Apache Software Foundation (ASF) under one or more
+ * contributor license agreements. See the NOTICE file distributed with
+ * this work for additional information regarding copyright ownership.
+ * The ASF licenses this file to You under the Apache License, Version 2.0
+ * (the "License"); you may not use this file except in compliance with
+ * the License. You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+package org.apache.gobblin.example.generic;
+
+import java.io.IOException;
+import java.util.Properties;
+
+import org.apache.commons.cli.CommandLine;
+
+import lombok.SneakyThrows;
+import lombok.extern.slf4j.Slf4j;
+
+import org.apache.gobblin.annotation.Alias;
+import org.apache.gobblin.runtime.api.JobTemplate;
+import org.apache.gobblin.runtime.cli.CliObjectOption;
+import org.apache.gobblin.runtime.cli.PublicMethodsGobblinCliFactory;
+import org.apache.gobblin.runtime.embedded.EmbeddedGobblin;
+import org.apache.gobblin.util.JobConfigurationUtils;
+
+
+/**
+ * A class that allows Gobblin cli to run a single pull file (in a blocking
manner) and exit on completion
+ * In contrast, a Gobblin standalone service will run forever polling
+ * for new pull files in the configured directory
+ */
+@Slf4j
+public class OneShotRunner extends EmbeddedGobblin {
+ @Alias(value = "oneShot", description = "Gobblin command that runs one pull
file in standalone or map-reduce mode")
+ public static class CliFactory extends PublicMethodsGobblinCliFactory {
+
+
+ public CliFactory() {
+ super(OneShotRunner.class);
+ }
+
+ @Override
+ public EmbeddedGobblin constructEmbeddedGobblin(CommandLine cli) throws
JobTemplate.TemplateException, IOException {
+ String[] leftoverArgs = cli.getArgs();
+ if (leftoverArgs.length != 0) {
+ throw new RuntimeException("Unexpected number of arguments.");
+ }
+ return new OneShotRunner();
+ }
+
+ @Override
+ public String getUsageString() {
+ return "[OPTIONS]";
+ }
+ }
+
+ @SneakyThrows
+ @CliObjectOption(description = "Runs the job in MR mode")
+ public OneShotRunner mrMode() {
+ super.mrMode();
+ return this;
+ }
+
+ @CliObjectOption(description = "Sets the base configuration file")
+ public OneShotRunner baseConf(String baseConfFile) {
+ log.info("Configured with baseConf file = {}", baseConfFile);
+ try {
+ Properties sysConfig =
JobConfigurationUtils.fileToProperties(baseConfFile);
+ log.debug("Loaded up base config: {}", sysConfig);
+ sysConfig.entrySet()
+ .stream()
+ .forEach(pair -> super.sysConfig(pair.getKey().toString(),
pair.getValue().toString()));
+
+ } catch (Exception e) {
+ throw new RuntimeException("Failed to load configuration from base
config file : " + baseConfFile, e);
+ }
+ return this;
+ }
+
+ @CliObjectOption(description = "Sets the application configuration file")
+ public OneShotRunner appConf(String appConfFile) {
+ super.jobFile(appConfFile);
+ return this;
+ }
+
+ public OneShotRunner() {
+ super("Generic");
+ }
+
+}
diff --git
a/gobblin-example/src/test/java/org/apache/gobblin/example/TestOneShotRunner.java
b/gobblin-example/src/test/java/org/apache/gobblin/example/TestOneShotRunner.java
new file mode 100644
index 0000000..b89e82f
--- /dev/null
+++
b/gobblin-example/src/test/java/org/apache/gobblin/example/TestOneShotRunner.java
@@ -0,0 +1,43 @@
+/*
+ * Licensed to the Apache Software Foundation (ASF) under one or more
+ * contributor license agreements. See the NOTICE file distributed with
+ * this work for additional information regarding copyright ownership.
+ * The ASF licenses this file to You under the Apache License, Version 2.0
+ * (the "License"); you may not use this file except in compliance with
+ * the License. You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+package org.apache.gobblin.example;
+
+import java.net.URL;
+
+import org.apache.hadoop.fs.Path;
+import org.testng.Assert;
+import org.testng.annotations.Test;
+
+import org.apache.gobblin.example.generic.OneShotRunner;
+import org.apache.gobblin.runtime.api.Configurable;
+
+
+public class TestOneShotRunner {
+
+ @Test
+ public void testConfiguration() {
+ OneShotRunner runner = new OneShotRunner();
+ URL appConfResource =
getClass().getClassLoader().getResource("appConf.conf");
+ URL baseConfResource =
getClass().getClassLoader().getResource("baseConf.conf");
+ runner.appConf("file://" + appConfResource.getFile());
+ runner.baseConf("file://" + baseConfResource.getFile());
+ Assert.assertEquals(runner.getJobFile().get(), new Path("file://" +
appConfResource.getPath()));
+ Configurable resolvedSysConfig = runner.getSysConfig();
+ Assert.assertEquals(resolvedSysConfig.getConfig().getString("test.key1"),
"value1");
+ Assert.assertEquals(resolvedSysConfig.getConfig().getString("test.key2"),
"value2");
+ }
+}
diff --git a/gobblin-example/src/test/resources/appConf.conf
b/gobblin-example/src/test/resources/appConf.conf
new file mode 100644
index 0000000..791a456
--- /dev/null
+++ b/gobblin-example/src/test/resources/appConf.conf
@@ -0,0 +1 @@
+test.key2=value2-override
diff --git a/gobblin-example/src/test/resources/baseConf.conf
b/gobblin-example/src/test/resources/baseConf.conf
new file mode 100644
index 0000000..6179ef3
--- /dev/null
+++ b/gobblin-example/src/test/resources/baseConf.conf
@@ -0,0 +1,2 @@
+test.key1=value1
+test.key2=value2
diff --git
a/gobblin-runtime/src/main/java/org/apache/gobblin/runtime/embedded/EmbeddedGobblin.java
b/gobblin-runtime/src/main/java/org/apache/gobblin/runtime/embedded/EmbeddedGobblin.java
index d723ff8..ce99dbf 100644
---
a/gobblin-runtime/src/main/java/org/apache/gobblin/runtime/embedded/EmbeddedGobblin.java
+++
b/gobblin-runtime/src/main/java/org/apache/gobblin/runtime/embedded/EmbeddedGobblin.java
@@ -38,7 +38,6 @@ import java.util.concurrent.locks.ReentrantLock;
import org.apache.avro.SchemaBuilder;
import org.apache.commons.lang3.ClassUtils;
-import org.apache.gobblin.runtime.job_spec.JobSpecResolver;
import org.apache.hadoop.conf.Configuration;
import org.apache.hadoop.fs.FileSystem;
import org.apache.hadoop.fs.Path;
@@ -64,6 +63,13 @@ import com.linkedin.data.template.DataTemplate;
import com.typesafe.config.Config;
import com.typesafe.config.ConfigFactory;
+import javassist.bytecode.ClassFile;
+import javax.annotation.Nullable;
+import lombok.AccessLevel;
+import lombok.Data;
+import lombok.Getter;
+import lombok.extern.slf4j.Slf4j;
+
import org.apache.gobblin.configuration.ConfigurationKeys;
import org.apache.gobblin.configuration.State;
import org.apache.gobblin.instrumented.extractor.InstrumentedExtractorBase;
@@ -82,15 +88,16 @@ import org.apache.gobblin.runtime.api.JobExecutionResult;
import org.apache.gobblin.runtime.api.JobSpec;
import org.apache.gobblin.runtime.api.JobTemplate;
import org.apache.gobblin.runtime.api.SpecNotFoundException;
-import
org.apache.gobblin.runtime.cli.ConstructorAndPublicMethodsGobblinCliFactory;
import org.apache.gobblin.runtime.cli.CliObjectOption;
import org.apache.gobblin.runtime.cli.CliObjectSupport;
+import
org.apache.gobblin.runtime.cli.ConstructorAndPublicMethodsGobblinCliFactory;
import org.apache.gobblin.runtime.cli.NotOnCli;
import org.apache.gobblin.runtime.instance.SimpleGobblinInstanceEnvironment;
import org.apache.gobblin.runtime.instance.StandardGobblinInstanceDriver;
import org.apache.gobblin.runtime.job_catalog.ImmutableFSJobCatalog;
import
org.apache.gobblin.runtime.job_catalog.PackagedTemplatesJobCatalogDecorator;
import org.apache.gobblin.runtime.job_catalog.StaticJobCatalog;
+import org.apache.gobblin.runtime.job_spec.JobSpecResolver;
import org.apache.gobblin.runtime.job_spec.ResolvedJobSpec;
import org.apache.gobblin.runtime.plugins.GobblinInstancePluginUtils;
import org.apache.gobblin.runtime.plugins.PluginStaticKeys;
@@ -102,13 +109,6 @@ import org.apache.gobblin.util.HadoopUtils;
import org.apache.gobblin.util.PathUtils;
import org.apache.gobblin.util.PullFileLoader;
-import javassist.bytecode.ClassFile;
-import javax.annotation.Nullable;
-import lombok.AccessLevel;
-import lombok.Data;
-import lombok.Getter;
-import lombok.extern.slf4j.Slf4j;
-
/**
* A class used to run an embedded version of Gobblin. This class is only
intended for running a single Gobblin job.
@@ -147,6 +147,7 @@ public class EmbeddedGobblin {
private FullTimeout shutdownTimeout = new FullTimeout(100, TimeUnit.SECONDS);
private boolean dumpJStackOnTimeout = false;
private List<GobblinInstancePluginFactory> plugins = Lists.newArrayList();
+ @Getter
private Optional<Path> jobFile = Optional.absent();
public EmbeddedGobblin() {
@@ -417,10 +418,14 @@ public class EmbeddedGobblin {
public JobExecutionDriver runAsync() throws TimeoutException,
InterruptedException {
// Run function to distribute jars to workers in distributed mode
this.distributeJarsFunction.run();
+ log.debug("BuiltConfigMap: {}", this.builtConfigMap);
+ log.debug("DefaultSysConfig: {}", this.defaultSysConfig);
Config sysProps = ConfigFactory.parseMap(this.builtConfigMap)
.withFallback(this.defaultSysConfig);
+ log.debug("Merged SysProps:{}", sysProps);
Config userConfig = ConfigFactory.parseMap(this.userConfigMap);
+ log.debug("UserConfig: {}", userConfig);
JobSpec jobSpec;
if (this.jobFile.isPresent()) {
@@ -431,6 +436,8 @@ public class EmbeddedGobblin {
PullFileLoader.DEFAULT_JAVA_PROPS_PULL_FILE_EXTENSIONS,
PullFileLoader.DEFAULT_HOCON_PULL_FILE_EXTENSIONS);
Config jobConfig =
userConfig.withFallback(loader.loadPullFile(jobFilePath, sysProps, false));
+ log.debug("JobConfig: {}", jobConfig);
+
ImmutableFSJobCatalog.JobSpecConverter converter =
new
ImmutableFSJobCatalog.JobSpecConverter(jobFilePath.getParent(),
Optional.<String>absent());
jobSpec = converter.apply(jobConfig);
@@ -532,7 +539,8 @@ public class EmbeddedGobblin {
}
}
- private Configurable getSysConfig() {
+ @VisibleForTesting
+ public Configurable getSysConfig() {
return
DefaultConfigurableImpl.createFromConfig(ConfigFactory.parseMap(this.sysConfigOverrides).withFallback(this.defaultSysConfig));
}
diff --git
a/gobblin-runtime/src/main/java/org/apache/gobblin/runtime/mapreduce/CliMRJobLauncher.java
b/gobblin-runtime/src/main/java/org/apache/gobblin/runtime/mapreduce/CliMRJobLauncher.java
index a12d4a2..c580429 100644
---
a/gobblin-runtime/src/main/java/org/apache/gobblin/runtime/mapreduce/CliMRJobLauncher.java
+++
b/gobblin-runtime/src/main/java/org/apache/gobblin/runtime/mapreduce/CliMRJobLauncher.java
@@ -21,8 +21,6 @@ import java.io.IOException;
import java.util.Properties;
import java.util.UUID;
-import javax.annotation.Nullable;
-
import org.apache.hadoop.conf.Configuration;
import org.apache.hadoop.conf.Configured;
import org.apache.hadoop.util.GenericOptionsParser;
@@ -31,6 +29,9 @@ import org.apache.hadoop.util.ToolRunner;
import com.google.common.io.Closer;
+import javax.annotation.Nullable;
+import lombok.extern.slf4j.Slf4j;
+
import org.apache.gobblin.runtime.JobException;
import org.apache.gobblin.runtime.JobLauncher;
import org.apache.gobblin.runtime.app.ApplicationException;
@@ -45,6 +46,7 @@ import org.apache.gobblin.runtime.listeners.JobListener;
*
* @author Yinan Li
*/
+@Slf4j
public class CliMRJobLauncher extends Configured implements
ApplicationLauncher, JobLauncher, Tool {
private final Closer closer = Closer.create();
@@ -53,6 +55,8 @@ public class CliMRJobLauncher extends Configured implements
ApplicationLauncher,
private final MRJobLauncher mrJobLauncher;
public CliMRJobLauncher(Configuration conf, Properties jobProperties) throws
Exception {
+ log.debug("Configuration: {}", conf);
+ log.debug("Job properties: {}", jobProperties);
setConf(conf);
this.applicationLauncher = this.closer.register(new
ServiceBasedAppLauncher(jobProperties,
jobProperties.getProperty(ServiceBasedAppLauncher.APP_NAME,
"CliMRJob-" + UUID.randomUUID())));
diff --git
a/gobblin-runtime/src/main/java/org/apache/gobblin/runtime/mapreduce/MRJobLauncher.java
b/gobblin-runtime/src/main/java/org/apache/gobblin/runtime/mapreduce/MRJobLauncher.java
index 1b89ba3..720aa8c 100644
---
a/gobblin-runtime/src/main/java/org/apache/gobblin/runtime/mapreduce/MRJobLauncher.java
+++
b/gobblin-runtime/src/main/java/org/apache/gobblin/runtime/mapreduce/MRJobLauncher.java
@@ -64,6 +64,8 @@ import com.typesafe.config.Config;
import com.typesafe.config.ConfigFactory;
import com.typesafe.config.ConfigValue;
+import lombok.extern.slf4j.Slf4j;
+
import org.apache.gobblin.broker.SharedResourcesBrokerFactory;
import org.apache.gobblin.broker.gobblin_scopes.GobblinScopeTypes;
import org.apache.gobblin.broker.gobblin_scopes.JobScopeInstance;
@@ -122,6 +124,7 @@ import
org.apache.gobblin.util.reflection.RestrictedFieldAccessingUtils;
*
* @author Yinan Li
*/
+@Slf4j
public class MRJobLauncher extends AbstractJobLauncher {
private static final String INTERRUPT_JOB_FILE_NAME = "_INTERRUPT_JOB";
@@ -253,6 +256,9 @@ public class MRJobLauncher extends AbstractJobLauncher {
jobProps.getProperty(ConfigurationKeys.MAXIMUM_JAR_COPY_RETRY_TIMES_KEY))
: MAXIMUM_JAR_COPY_RETRY_TIMES_DEFAULT;
+ // One of the most common user mistakes is mis-configuring the FileSystem
scheme (e.g. file versus hdfs)
+ log.info("Configured fs:{}", fs);
+ log.debug("Configuration: {}", conf);
startCancellationExecutor();
}
diff --git
a/gobblin-utility/src/main/java/org/apache/gobblin/runtime/cli/GobblinCli.java
b/gobblin-utility/src/main/java/org/apache/gobblin/runtime/cli/GobblinCli.java
index aa3cbd7..6a287db 100644
---
a/gobblin-utility/src/main/java/org/apache/gobblin/runtime/cli/GobblinCli.java
+++
b/gobblin-utility/src/main/java/org/apache/gobblin/runtime/cli/GobblinCli.java
@@ -22,9 +22,6 @@ import com.google.common.collect.Sets;
import org.apache.gobblin.annotation.Alias;
import org.apache.gobblin.util.ClassAliasResolver;
-import java.util.ArrayList;
-import java.util.List;
-
/**
* Instantiates a {@link CliApplication} and runs it.
@@ -47,9 +44,11 @@ public class GobblinCli {
} catch (ReflectiveOperationException roe) {
System.err.println("Could not find an application with alias " + alias);
printUsage(resolver);
+ System.exit(1);
} catch (Throwable t) {
System.out.println("Error: " + t.getMessage());
t.printStackTrace();
+ System.exit(2);
}
}