추가 읽기

추가 읽기

Raspberry Pi(Stretch)를 재부팅하면 데몬이 /run/user/1000존재하지 않기 때문에 시작되지 않습니다. 이것은 내 유닛 파일입니다:

[Unit]
Description=SBFspot Upload Daemon

[Service]
User=pi
Type=forking
TimeoutStopSec=60
ExecStart=/usr/local/bin/sbfspot.3/SBFspotUploadDaemon -p /run/user/1000/sbfspotupload.pid 2>&1> /dev/null
PIDFile=/run/user/1000/sbfspotupload.pid
Restart=no
RestartSec=15
SuccessExitStatus=SIGKILL

[Install]
WantedBy=default.target

몇 번 다시 시도한 후에 제대로 작동 하도록 구성했지만 Restart=on-failure실제로는 내가 원하는 것이 아닙니다. 데몬이 /run/user/1000설치를 기다리기를 원합니다 . 시도했지만 After=run-user-1000.mount여전히 실패했습니다.

이것이 가능합니까, 아니면 고집해야합니까 Restart=on-failure?

답변1

/run/user/1000물론 사용자 #1000이 로그인하거나 명시적으로 xyr 사용자별 서비스 관리를 시작하기 전까지는 존재하지 않습니다. 이를 사용하기 위한 전체 메커니즘이 존재해서는 안 됩니다.

이 프로그램의 버그 #215당신이 생각하는 것보다 훨씬 더 깊습니다. 이 서비스 단위 파일은 매우 잘못되었습니다.프로그램 자체의 동작도 마찬가지이다.. 시스템화된 서비스 단위의 기본을 실제로 이해하지 못하는 데 기반을 둔 화물 매니아 프로그래밍이 많이 있습니다.

  • 서비스 단위는 쉘 스크립트가 아닙니다. 시스템 매뉴얼하다설명하다. 여기에서 설정하면 서비스 프로그램이 일부 추가 매개변수 와 ExecStart함께 실행됩니다 .2>&1>/dev/null
  • 서비스 관리자는 하나의 서비스만 실행 중인지 확인했습니다. 여기에 추가된 코드는 모두 불필요한 쓰레기입니다.
  • 불안정하고 위험한 PID 파일 메커니즘은아니요사용. 적절한 서비스 관리에는 자리가 없습니다.
  • 서비스 관리자는 데몬 컨텍스트에서 서비스 호출도 처리합니다. 다른 많은 코드 main()는 다음과 같습니다.반품악마화 오류에 근거한 불필요한 쓰레기.
    • 프로그램이 fork()전혀 실행되어서는 안 되며 서비스 준비 메커니즘이 지정되어서도 안 됩니다 Type=forking. 현실 세계의 많은 프로그램과 마찬가지로 이 프로그램도아니요먼저 포크 준비 프로토콜에 대해 이야기해 보겠습니다.
    • 계획은이미슈퍼유저로 실행합니다. User=root불필요하며 서비스를 실제로 재설계해야 합니다.아니요슈퍼유저 권한으로 실행해야 하지만 대신 권한이 없는 전용 서비스 계정의 후원으로 실행됩니다.
    • 서비스 관리자는이미표준 출력과 오류를 기록하고 이 프로그램보다 더 나은 작업을 수행합니다. 자체 개발한 이 로깅 시스템은 전체 파일 시스템을 채울 때까지만 로그 파일을 증가시키며, 수퍼유저용으로 예약된 모든 비상 공간을 소비합니다.
    • 귀하의 로그는 표준 오류일 뿐이며 C++에서 std::clog.
    • 실제로,fork()표준 오류로 리디렉션되는 모든 코드사용해서는 안됩니다. 서비스 관리 핸들모두세션 리더에서 작업 디렉터리로, umask에서 표준 I/O로 이동하며 올바르게 수행됩니다. 이 앱은 그렇게 하지 않으며, 그렇게 시도해서도 안 됩니다.어느서비스 관리자에서 사용할 때의 모습입니다.

      Boost에서 얻은 모든 것이 잘못되었습니다.

  • 세 가지 서비스 단위는 불필요한 유지 관리 비용입니다. 설정 만 After다르며 하나로 병합할 수 있습니다.
  • 무례한 해고는 성공이 아닙니다. 있다는 점을 고려하면이미종료 시 파일 정리와 관련된 문제 SuccessExitStatus=SIGKILL는 버그입니다. 정상적인 종료는 정상적으로 전달되어야 SIGTERM하며 SIGKILL예외적인 것으로 간주되어야 합니다. (물론 output이미 설명했듯이 전체 파일 메커니즘은 제대로 구현되지 않은 로컬 로깅 메커니즘이므로 서비스 관리에서 사용해서는 안됩니다.) 이것이 systemd의 기본 설정입니다.
  • 데이터베이스 개체 및 기타 콘텐츠에 대한 소멸자를 실행해야 합니다.main()떠나지 마세요 exit().

올바르게 구현되고 서비스 관리자(daemontools, runit, s6, nosh, systemd 등)에서 실행되는 데몬은 훨씬 더 짧습니다.

//지금까지 마찬가지
무효 pvo_upload(무효)
{
    std::clog << "데몬 프로세스 시작..." << std::endl;

    공공 서비스 코드();

    std::clog << "데몬 중지..." << std::endl;
}

int main(int argc, char *argv[])
{
    정수 c;
    const char *config_file = "";

    /* 명령줄 구문 분석*/
    동시에(1)
    {
        정적 구조 옵션 long_options[] =
        {
            {"구성 파일",required_argument,0,'c'},
            { 0, 0, 0, 0 }
        };

        int 옵션 인덱스 = 0;
        c = getopt_long(argc, argv, "c:", long_options, &option_index);

        if (c == -1) 인터럽트;

        스위치 (c)
        {
            사례 "c":
                구성 파일=optarg;
                나머지;
            기본:
                EXIT_FAILURE를 반환합니다.
                나머지;
        }
    }

    if (cfg.readSettings(argv[0], config_file) != 구성::CFG_OK)
        EXIT_FAILURE를 반환합니다.

    std::clog << "SBFspotUploadDaemon 버전 시작 중" << 버전 << std::endl;

    // 데이터베이스에 접근 가능한지 확인
    db_SQL_Base db = db_SQL_Base();
    db.open(cfg.getSqlHostname(), cfg.getSqlUsername(), cfg.getSqlPassword(), cfg.getSqlDatabase());
    if (!db.isopen())
    {
        std::clog << "데이터베이스를 열 수 없습니다. 구성을 확인하십시오." << std::endl;
        EXIT_FAILURE를 반환합니다.
    }

    // 데이터베이스 버전 확인
    int 스키마_버전 = 0;
    db.get_config(SQL_SCHEMAVERSION, 스키마_버전);
    db.close();

    if (schema_version < SQL_MINIMUM_SCHEMA_VERSION)
    {
        std::clog << "데이터베이스를 버전으로 업그레이드" << SQL_MINIMUM_SCHEMA_VERSION << std::endl;
        EXIT_FAILURE를 반환합니다.
    }

    //신호 처리기를 설치합니다.
    // 서비스 관리자가 보낸 서비스 중지 신호에 응답합니다.
    signal(SIGTERM, 핸들러);

    // 데몬 루프 시작
    pvo_upload();

    return 종료_성공;
}

그리고 서비스 단위도 더 짧습니다.

[단위]
설명=SBFspot 업로드 데몬
이후=mysql.service mariadb.service network.target

[제공하다]
유형=단순
시간 초과 중지 초=10
ExecStart=/usr/local/bin/sbfspot.3/SBFspotUploadDaemon
다시 시작=성공

[설치하다]
WantedBy=다중 사용자.대상

systemctl status로그 출력을 사용하고 볼 수 있습니다 journalctl( -u필요한 경우 옵션 및 서비스 이름 포함).

추가 읽기

관련 정보