繁体   English   中英

在 cron 下运行时 Java 作业未写入文件

[英]Java job not writing to file when running under cron

提前道歉,我的 Java 是垃圾。 我已经(从其他人那里)拼凑了一个脚本,该脚本执行一个脚本,将输出假脱机到一个文本文件,然后我将其发送到另一个系统。 这是 crontab 条目

jcb@LWS-DEV4B:~/bridge/heartbeat$ crontab -l
*/2 * * * * (cd /home/jcb/bridge/heartbeat/; ./hb_execute_bridge_util_mem_usage.sh)
*/5 * * * * (cd /home/jcb/bridge/heartbeat/; ./hb_bridge_status_cron.sh)

当我手动调用 java 程序时,它可以工作。

jcb@LWS-DEV4B:~/bridge/heartbeat$ java -classpath /home/jcb/bridge/heartbeat/ojdbc6.jar:. hb_bridge_util_mem_usage
jcb@LWS-DEV4B:~/bridge/heartbeat$ ls -ltr hb_bridge_util_mem_usage.txt
-rwxr-xr-x 1 jcb jcb 14919 Oct 28 11:55 hb_bridge_util_mem_usage.txt

当我调用调用 java 程序的 shell 脚本时,它可以工作。

jcb@LWS-DEV4B:~/bridge/heartbeat$ ./hb_execute_bridge_util_mem_usage.sh
jcb@LWS-DEV4B:~/bridge/heartbeat$ ls -ltr hb_bridge_util_mem_usage.txt
-rwxr-xr-x 1 jcb jcb 14919 Oct 28 11:59 hb_bridge_util_mem_usage.txt

但是,cronjob 不会假脱机任何输出。

-rwxr-xr-x 1 jcb jcb       0 Oct 28 11:52 hb_bridge_util_mem_usage.txt

我在论坛中阅读了一些关于等待进程的内容,我添加了这些内容以查看它是否有所作为。 这是我的shell脚本:

#!/bin/bash
java -classpath /home/jcb/bridge/heartbeat/ojdbc6.jar:. hb_bridge_util_mem_usage

这是我的 java 程序,再次:等待、销毁、获取输入是我后来添加的东西,看看它是否会有所作为:

import java.io.File;
import java.io.FileInputStream;
import java.io.InputStream;
import java.sql.Connection;
import java.sql.DriverManager;
import java.sql.PreparedStatement;

public class hb_bridge_util_mem_usage {

  public static Connection getConnection() throws Exception {
    String driver = "oracle.jdbc.driver.OracleDriver";
    String url = "jdbc:oracle:thin:@???";
    String username = "???";
    String password = "???";
    Class.forName(driver);
    Connection conn = DriverManager.getConnection(url, username, password);
    return conn;
  }

  public static void main(String[] args)throws Exception {
    String id = "001";
    String fileName = "hb_bridge_util_mem_usage.txt";

    ProcessBuilder processBuilder = new ProcessBuilder();

    processBuilder.command("bash", "-c", "util_mem_usage | tee /home/jcb/bridge/heartbeat/hb_bridge_util_mem_usage.txt");

    Process process = processBuilder.start();
    InputStream in = process.getInputStream();
    InputStream error = process.getErrorStream();
    for (int i = 0; i < error.available(); i++) {
           System.out.println("" + error.read());
         }

    // wait for 10 seconds and then destroy the process
    Thread.sleep(10000);
    process.destroy();

    FileInputStream fis = null;
    PreparedStatement pstmt = null;
    Connection conn = null;
    try {
      conn = getConnection();
      conn.setAutoCommit(false);
      File file = new File(fileName);
      fis = new FileInputStream(file);
      pstmt = conn.prepareStatement("insert into hb_bridge_util_mem_usage(id, fileName, fileBody) values (?, ?, ?)");
      pstmt.setString(1, id);
      pstmt.setString(2, fileName);
      pstmt.setAsciiStream(3, fis, (int) file.length());
      pstmt.executeUpdate();
      conn.commit();
    } catch (Exception e) {
      System.err.println("Error: " + e.getMessage());
      e.printStackTrace();
    } finally {
      pstmt.close();
      fis.close();
      conn.close();
    }
  }

问题与您的java代码无关; java 不会因为 cron 调用它而“运行不同”。

有两种可能的解释:

进程的用户

进程归用户所有。 他们的权限,例如访问目录和文件时,由该用户被允许做什么来控制。 例如,如果您将/home/barry文件夹设置为“用户可读/可写/可见,但其他任何人都可读/可见”,即如果您在/home目录中运行ls -la并且您看到:

rwxr-xr-x barry

然后,如果您以 barry 身份登录并启动一个尝试执行的 Java 应用程序:

Files.write("Hello!", Paths.get("/home/barry/test.txt"));

它会正常工作。 但是,如果您然后以用户jane运行它,它将失败:该进程与用户jane具有相同的权限,而用户jane无权在该文件夹中写入。

cron 以某个用户身份运行您的应用程序。 取决于您如何配置 cron。 如果所述用户无权写入文件,您有自己的解释。 简单的解决方法是,无论您的应用程序在何处尝试为正在运行它的任何用户 cron 编写一个可写的位置,或者,您将 cron 配置为在不同的用户下运行这个,或者,您通过su运行命令这让您可以以不同的用户身份运行它。 但是,仅当您以root身份调用su本身时,才能使用su以其他用户身份运行某些内容。

安全说明:在许多配置下,有一个每个用户的 cron 表(然后这些任务以该用户身份运行),以及一个全局 crontable 和其中的所有内容都以 root 身份运行 以 root 身份运行应用程序极其危险; 任何问题都可以消灭或接管整个系统。 您不应该以 root 身份运行。 因此,如果这是在全局 cron 表中并且以 root 身份运行,那么您绝对应该执行su 我们可以或多或少地相信su不会搞砸,因为它会以例如barry的权限调用您的java应用程序,至少这样您就不必再信任java 出于一个简单的原因,您不应该信任java :java 是一个复杂的可执行文件,可以运行任意代码。 NASA 是否写了它并不重要:您不能像极其简单的su命令一样信任这种复杂性。

当前工作目录

我认为cd东西意味着这不可能,但我不能 100% 确定 java 进程的工作目录最终是你cd到的目录。 你可能想检查一下。 例如,通过写入System.getProperty("user.dir") (这是一个命名相当奇怪的属性,它为您提供当前工作目录),或将new File(".").toAbsolutePath()打印到绝对位置,例如/home/foo/test.txt ,其中/home/foo具有rwxrwxrwx权限(通过运行sudo chmod 777 /home/foo ),在将该 foo 目录rwxrwxrwx于此测试目的之后。

然后让 cron 做它的事情,您可以使用该文件来跟踪调试问题时 Java 进程发出的内容。

问题是 Java 无法执行 C 程序“util_mem_usage”,尽管我到处都有“su”命令。 我的解决方案是将这个命令分离到一个 shell scipt 中。 这些路径是 C 程序运行所需的(可能也是 Java 一直在默默挣扎的东西)。

#!/bin/bash
PATH=/home/jcb/bin:/usr/bin/
**LD_LIBRARY_PATH=/home/jcb/lib
PROJECT_ROOT=/home/jcb
export LD_LIBRARY_PATH
export PROJECT_ROOT**
util_mem_usage | tee /home/jcb/bridge/heartbeat/hb_bridge_util_mem_usage.txt

我的 java 程序然后调用它而不是 C 实用程序

processBuilder.command("bash", "-c", "/home/jcb/bridge/heartbeat/hb_get_bridge_util_mem_usage.sh");

这似乎不是一个优雅的解决方案,但它有效......

暂无
暂无

声明:本站的技术帖子网页,遵循CC BY-SA 4.0协议,如果您需要转载,请注明本站网址或者原文地址。任何问题请咨询:yoyou2525@163.com.

 
粤ICP备18138465号  © 2020-2024 STACKOOM.COM