【问题标题】:Worker process cannot be executed in a Java Tomcat server deployed to Heroku无法在部署到 Heroku 的 Java Tomcat 服务器中执行工作进程
【发布时间】:2017-03-13 17:42:17
【问题描述】:

我有 1 个 web 和 1 个工作进程使用由 2 个通道/队列组成的 CloudAMQP 库相互通信(1 个通道是从 web 发送简单消息,另一个通道是从worker)。由于我以WAR 文件格式部署我的webapp,我必须通过创建一个本地Maven 存储库并将我的worker 类放入一个jar 中,并包含将文件放入WEB-INF/lib 文件夹的依赖项,以便我可以执行使用从maven-war-plugin 工件生成的worker sh 脚​​本的工作进程。

worker sh 脚本:

BASEDIR=`dirname $0`/..
BASEDIR=`(cd "$BASEDIR"; pwd)`



# OS specific support.  $var _must_ be set to either true or false.
cygwin=false;
darwin=false;
case "`uname`" in
  CYGWIN*) cygwin=true ;;
  Darwin*) darwin=true
           if [ -z "$JAVA_VERSION" ] ; then
             JAVA_VERSION="CurrentJDK"
           else
             echo "Using Java version: $JAVA_VERSION"
           fi
           if [ -z "$JAVA_HOME" ] ; then
             JAVA_HOME=/System/Library/Frameworks/JavaVM.framework/Versions/${JAVA_VERSION}/Home
           fi
           ;;
esac

if [ -z "$JAVA_HOME" ] ; then
  if [ -r /etc/gentoo-release ] ; then
    JAVA_HOME=`java-config --jre-home`
  fi
fi

# For Cygwin, ensure paths are in UNIX format before anything is touched
if $cygwin ; then
  [ -n "$JAVA_HOME" ] && JAVA_HOME=`cygpath --unix "$JAVA_HOME"`
  [ -n "$CLASSPATH" ] && CLASSPATH=`cygpath --path --unix "$CLASSPATH"`
fi

# If a specific java binary isn't specified search for the standard 'java' binary
if [ -z "$JAVACMD" ] ; then
  if [ -n "$JAVA_HOME"  ] ; then
    if [ -x "$JAVA_HOME/jre/sh/java" ] ; then
      # IBM's JDK on AIX uses strange locations for the executables
      JAVACMD="$JAVA_HOME/jre/sh/java"
    else
      JAVACMD="$JAVA_HOME/bin/java"
    fi
  else
    JAVACMD=`which java`
  fi
fi

if [ ! -x "$JAVACMD" ] ; then
  echo "Error: JAVA_HOME is not defined correctly."
  echo "  We cannot execute $JAVACMD"
  exit 1
fi

if [ -z "$REPO" ]
then
  REPO="$BASEDIR"/repo
fi

CLASSPATH=$CLASSPATH_PREFIX:"$BASEDIR"/etc:"$REPO"/com/rabbitmq/amqp-client/3.3.4/amqp-client-3.3.4.jar:"$REPO"/javax/servlet/jstl/1.2/jstl-1.2.jar:"$REPO"/com/example/worker/1.0/worker-1.0.jar:"$REPO"/cloudamqp/example/amqpexample/1.0-SNAPSHOT/amqpexample-1.0-SNAPSHOT.war
EXTRA_JVM_ARGUMENTS=""

# For Cygwin, switch paths to Windows format before running java
if $cygwin; then
  [ -n "$CLASSPATH" ] && CLASSPATH=`cygpath --path --windows "$CLASSPATH"`
  [ -n "$JAVA_HOME" ] && JAVA_HOME=`cygpath --path --windows "$JAVA_HOME"`
  [ -n "$HOME" ] && HOME=`cygpath --path --windows "$HOME"`
  [ -n "$BASEDIR" ] && BASEDIR=`cygpath --path --windows "$BASEDIR"`
  [ -n "$REPO" ] && REPO=`cygpath --path --windows "$REPO"`
fi

exec "$JAVACMD" $JAVA_OPTS \
  $EXTRA_JVM_ARGUMENTS \
  -classpath "$CLASSPATH" \
  -Dapp.name="worker" \
  -Dapp.pid="$$" \
  -Dapp.repo="$REPO" \
  -Dbasedir="$BASEDIR" \
  WorkerProcess \
  "$@"

worker sh 脚本随后被 Heroku Procfile 引用:

web: java $JAVA_OPTS -jar target/dependency/webapp-runner.jar --port $PORT target/*.war
worker: sh target/bin/worker

我使用 heroku local -f Procfile.windows 在本地测试了该应用程序,并且一切正常。但是,当我部署到 Heroku 时(我也尝试使用 Heroku CLI 部署和 git),只有 web Procfile 可以正确执行。当我检查日志时,工作进程返回error 127,说它无法打开target\bin\worker 脚本。我试图用谷歌搜索 error 127 对 heroku 的含义,但到目前为止还没有匹配项,而且我不知道远程部署的应用程序无法打开 target\bin\worker 的原因,即使它在我的本地部署中运行良好.任何帮助将不胜感激。 下面是分别来自 Heroku、servlet 类、worker 类和 POM 的完整错误日志:

2016-10-31T14:27:32.629768+00:00 heroku[slug-compiler]: Slug compilation finished
2016-10-31T14:27:34.807925+00:00 heroku[web.1]: State changed from down to starting
2016-10-31T14:27:34.941663+00:00 heroku[worker.1]: State changed from down to starting
2016-10-31T14:27:37.334213+00:00 heroku[worker.1]: Starting process with command `sh target/bin/worker`
2016-10-31T14:27:37.825597+00:00 heroku[worker.1]: State changed from starting to up
2016-10-31T14:27:38.100208+00:00 app[worker.1]: sh: 0: Can't open target/bin/worker
2016-10-31T14:27:38.104979+00:00 heroku[worker.1]: State changed from up to crashed
2016-10-31T14:27:38.104979+00:00 heroku[worker.1]: State changed from crashed to starting
2016-10-31T14:27:38.291551+00:00 heroku[web.1]: Starting process with command `java $JAVA_OPTS -jar target/dependency/webapp-runner.jar $WEBAPP_RUNNER_OPTS --port 54481 target/amqpexample-1.0-SNAPSHOT.war`
2016-10-31T14:27:40.725610+00:00 app[web.1]: Setting JAVA_TOOL_OPTIONS defaults based on dyno size. Custom settings will override them.
2016-10-31T14:27:40.732741+00:00 app[web.1]: Picked up JAVA_TOOL_OPTIONS: -Xmx350m -Xss512k -Dfile.encoding=UTF-8
2016-10-31T14:27:41.385588+00:00 app[web.1]: Expanding amqpexample-1.0-SNAPSHOT.war into /app/target/tomcat.54481/webapps/expanded
2016-10-31T14:27:41.385722+00:00 app[web.1]: Adding Context  for /app/target/tomcat.54481/webapps/expanded
2016-10-31T14:27:41.817336+00:00 heroku[worker.1]: Starting process with command `sh target/bin/worker`
2016-10-31T14:27:42.172560+00:00 app[web.1]: INFO: Initializing ProtocolHandler ["http-nio-54481"]
2016-10-31T14:27:42.172549+00:00 app[web.1]: Oct 31, 2016 2:27:42 PM org.apache.coyote.AbstractProtocol init
2016-10-31T14:27:42.201060+00:00 app[web.1]: Oct 31, 2016 2:27:42 PM org.apache.tomcat.util.net.NioSelectorPool getSharedSelector
2016-10-31T14:27:42.201064+00:00 app[web.1]: INFO: Using a shared selector for servlet write/read
2016-10-31T14:27:42.205036+00:00 app[web.1]: Oct 31, 2016 2:27:42 PM org.apache.catalina.core.StandardService startInternal
2016-10-31T14:27:42.205038+00:00 app[web.1]: INFO: Starting service Tomcat
2016-10-31T14:27:42.206587+00:00 app[web.1]: Oct 31, 2016 2:27:42 PM org.apache.catalina.core.StandardEngine startInternal
2016-10-31T14:27:42.206588+00:00 app[web.1]: INFO: Starting Servlet Engine: Apache Tomcat/8.0.30
2016-10-31T14:27:42.378327+00:00 heroku[worker.1]: State changed from starting to up
2016-10-31T14:27:42.441771+00:00 app[web.1]: Oct 31, 2016 2:27:42 PM org.apache.catalina.startup.ContextConfig getDefaultWebXmlFragment
2016-10-31T14:27:42.441781+00:00 app[web.1]: INFO: No global web.xml found
2016-10-31T14:27:42.765321+00:00 heroku[web.1]: State changed from starting to up
2016-10-31T14:27:43.507545+00:00 app[worker.1]: sh: 0: Can't open target/bin/worker
2016-10-31T14:27:43.591348+00:00 heroku[worker.1]: Process exited with status 127
2016-10-31T14:27:43.603552+00:00 heroku[worker.1]: State changed from up to crashed
2016-10-31T14:27:44.410603+00:00 app[web.1]: Oct 31, 2016 2:27:44 PM org.apache.jasper.servlet.TldScanner scanJars
2016-10-31T14:27:44.410621+00:00 app[web.1]: INFO: At least one JAR was scanned for TLDs yet contained no TLDs. Enable debug logging for this logger for a complete list of JARs that were scanned but no TLDs were found in them. Skipping unneeded JARs during scanning can improve startup time and JSP compilation time.
2016-10-31T14:27:44.498715+00:00 app[web.1]: Oct 31, 2016 2:27:44 PM org.apache.coyote.AbstractProtocol start
2016-10-31T14:27:44.498718+00:00 app[web.1]: INFO: Starting ProtocolHandler ["http-nio-54481"]
2016-10-31T14:27:47.410949+00:00 heroku[router]: at=info method=GET path="/" host=amqpexample.herokuapp.com request_id=334f7e05-d4e5-4f78-a444-1e6e7403e52c fwd="14.192.210.168" dyno=web.1 connect=1ms service=4305ms status=200 bytes=370
2016-10-31T14:27:50.003897+00:00 heroku[router]: at=info method=GET path="/" host=amqpexample.herokuapp.com request_id=51c9fac7-6763-4374-9f2b-672f0d7f7be7 fwd="14.192.210.168" dyno=web.1 connect=1ms service=21ms status=200 bytes=295

Servlet 类(负责在刷新时显示缓冲区消息并等待从worker 发送的新消息):

package herokutest;

import com.rabbitmq.client.*;

import java.io.IOException;
import java.net.URISyntaxException;
import java.security.KeyManagementException;
import java.security.NoSuchAlgorithmException;
import javax.servlet.ServletConfig;
import javax.servlet.ServletException;
import javax.servlet.http.HttpServletRequest;
import javax.servlet.http.HttpServletResponse;

public class HelloWorld extends javax.servlet.http.HttpServlet {

    private final static String QUEUE_NAME = "hello";
    private final static String ANOTHER_QUEUE = "ANOTHER";

    public Channel channel;
    public Channel anotherChannel;
    public DefaultConsumer consumer;
    public  String message = "Temporary";

    public void init(final ServletConfig config) throws ServletException {
        try {
            createChannel();
        } catch (Exception e) {
            e.printStackTrace();
        }
        finally {
                consumer = new DefaultConsumer(anotherChannel) {
                    @Override
                    public void handleDelivery(String consumerTag, Envelope envelope, AMQP.BasicProperties properties, byte[] body) throws IOException {
                        String innerMessage = new String(body, "UTF-8");
                        message = innerMessage;
                    }
                };
                try {
                    anotherChannel.basicConsume(ANOTHER_QUEUE, true, consumer);
                } catch (IOException e) {
                    e.printStackTrace();
                }
        }
    }

    public void createChannel() throws NoSuchAlgorithmException, KeyManagementException, URISyntaxException, IOException {
        String uri = System.getenv("CLOUDAMQP_URL");
        if (uri == null) uri = "amqp://guest:guest@localhost";

        ConnectionFactory factory = new ConnectionFactory();
        factory.setUri(uri);
        factory.setRequestedHeartbeat(30);
        factory.setConnectionTimeout(30);
        Connection connection = factory.newConnection();
         channel = connection.createChannel();
         anotherChannel = connection.createChannel();

        channel.queueDeclare(QUEUE_NAME, false, false, false, null);
        anotherChannel.queueDeclare(ANOTHER_QUEUE, false, false, false, null);

    }


    protected void doGet(final HttpServletRequest request, final HttpServletResponse response) throws ServletException, IOException {

        String test="test";
       channel.basicPublish("", QUEUE_NAME, null, test.getBytes());
        request.setAttribute("message", message);
        request.getRequestDispatcher("/index.jsp").forward(request, response);

    }
}

Worker 类:(负责将消息Another message 发送回servlet)

import com.rabbitmq.client.*;

import java.io.IOException;

public class WorkerProcess {
    private final static String QUEUE_NAME = "hello";
    private final static String ANOTHER_QUEUE = "ANOTHER";
    static String message;



    public static void main(String[] argv) throws Exception {


        ConnectionFactory factory = new ConnectionFactory();

        String uri = System.getenv("CLOUDAMQP_URL");
            if (uri == null) uri = "amqp://guest:guest@localhost";
        factory.setUri(uri);
        factory.setRequestedHeartbeat(30);
        factory.setConnectionTimeout(30);

        Connection connection = factory.newConnection();

        Channel channel = connection.createChannel();
        final Channel anotherChannel = connection.createChannel();
        channel.queueDeclare(QUEUE_NAME, false, false, false, null);
        anotherChannel.queueDeclare(ANOTHER_QUEUE, false, false, false, null);
        System.out.println(" [*] Connected to Worker");

        final Consumer consumer = new DefaultConsumer(channel) {
            @Override
            public void handleDelivery(String consumerTag, Envelope envelope, AMQP.BasicProperties properties, byte[] body) throws IOException {

                message = new String(body, "UTF-8");
                String anotherMessage= "Another message";
                anotherChannel.basicPublish("", ANOTHER_QUEUE, null, anotherMessage.getBytes());
            }
        };
        channel.basicConsume(QUEUE_NAME, true, consumer);

    }

}

POM

<project xmlns="http://maven.apache.org/POM/4.0.0" xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
  xsi:schemaLocation="http://maven.apache.org/POM/4.0.0 http://maven.apache.org/xsd/maven-4.0.0.xsd">
  <modelVersion>4.0.0</modelVersion>

  <groupId>cloudamqp.example</groupId>
  <artifactId>amqpexample</artifactId>
  <version>1.0-SNAPSHOT</version>
  <packaging>war</packaging>

  <dependencies>
    <dependency>
      <groupId>com.rabbitmq</groupId>
      <artifactId>amqp-client</artifactId>
      <version>3.3.4</version>
    </dependency>
    <dependency>
    <groupId>javax.servlet</groupId>
    <artifactId>jstl</artifactId>
    <version>1.2</version>
  </dependency>
      <dependency>
          <groupId>javax.servlet</groupId>
          <artifactId>javax.servlet-api</artifactId>
          <version>3.0.1</version>
          <scope>provided</scope>
      </dependency>

<!-- This is my worker jar included as dependency -->
    <dependency>
      <groupId>com.example</groupId>
      <artifactId>worker</artifactId>
      <version>1.0</version>
    </dependency>
  </dependencies>
 <!-- My local repository containing my worker .jar file-->
  <repositories>
    <repository>
      <id>project.local</id>
      <name>project</name>
      <url>file:${project.basedir}/localrepo</url>
    </repository>
  </repositories>


  <build>
    <plugins>
      <plugin>
        <groupId>com.heroku.sdk</groupId>
        <artifactId>heroku-maven-plugin</artifactId>
        <version>1.1.1</version>
      </plugin>


      <plugin>
        <groupId>org.apache.maven.plugins</groupId>
        <artifactId>maven-war-plugin</artifactId>
        <version>2.4</version>
        <configuration>
          <webResources>
            <resource>
              <directory>src/web</directory>
            </resource>
          </webResources>
            <archiveClasses>false</archiveClasses>
        </configuration>
      </plugin>

      <plugin>
        <groupId>org.codehaus.mojo</groupId>
        <artifactId>appassembler-maven-plugin</artifactId>
        <version>1.1.1</version>
        <configuration> 
          <assembleDirectory>target</assembleDirectory> 
          <programs>
            <program>
              <mainClass>WorkerProcess</mainClass>
              <name>worker</name>
            </program>
          </programs>
        </configuration>
        <executions>
          <execution>
            <phase>package</phase>
            <goals>
              <goal>assemble</goal>
            </goals>
          </execution>            
        </executions>
      </plugin>

      <plugin>
        <groupId>org.apache.maven.plugins</groupId>
        <artifactId>maven-dependency-plugin</artifactId>
        <version>2.3</version>
        <executions>
          <execution>
            <phase>package</phase>
            <goals><goal>copy</goal></goals>
            <configuration>
              <artifactItems>
                <artifactItem>
                  <groupId>com.github.jsimone</groupId>
                  <artifactId>webapp-runner</artifactId>
                  <version>8.0.30.2</version>
                  <destFileName>webapp-runner.jar</destFileName>
                </artifactItem>
              </artifactItems>
            </configuration>
          </execution>
        </executions>
      </plugin>

    </plugins>
  </build>  
</project>

【问题讨论】:

    标签: java maven tomcat servlets heroku


    【解决方案1】:

    这是日志中的重要信息:

    2016-10-31T14:27:43.507545+00:00 app[worker.1]: sh: 0: Can't open target/bin/worker
    

    您的 Maven 构建是否会生成此 target/bin/worker 脚本?

    我不希望 CLI 部署能够正常工作,因为默认情况下它不包含 target 目录。但您可以将其包含在 --include 选项中。

    【讨论】:

      猜你喜欢
      • 1970-01-01
      • 2015-07-05
      • 1970-01-01
      • 2015-05-21
      • 1970-01-01
      • 2013-08-22
      • 2015-09-07
      • 1970-01-01
      • 2020-10-10
      相关资源
      最近更新 更多