-1

In PHP i am building a hook system for a project I am working on right now. The system will check in the database for external files that need to executed if a hook is triggered.

To achieve this I was thinking of using curl, the only problem is curl blocks the rest of the code to execute. What I want is to just send an HTTP request to the URL given and not having to wait for a response at all. We don't care about the status. It's up to the customer to make sure there code is working.

The big challenge is that we still use PHP 5.5.9 :( So the solution should be working with that until we can upgrade to PHP 7.2

Any ideas or nudges for achieving this?

user3942918
  • 25,539
  • 11
  • 55
  • 67
Ronald Werkhoven
  • 144
  • 1
  • 14
  • Possible duplicate of [Async curl request in PHP](https://stackoverflow.com/questions/36171222/async-curl-request-in-php) – Justinas Jan 10 '19 at 07:48
  • 1
    Run a separated process in background to send the request. Even if you use async http request (whatever language you use), you still must wait for the request to be completed before you exit your script/program. – shawn Jan 10 '19 at 07:49
  • 5
    Upgrade your PHP first. 5.5 stopped getting *security fixes* **two and a half years ago** ! If I were your customer, I would not do business with you. – Bart Friederichs Jan 10 '19 at 07:53
  • @BartFriederichs tell me about it, would be nice if you convince the project manager, this just does not cut is any more :P – Ronald Werkhoven Jan 10 '19 at 08:09
  • There could be reasons not to upgrade, but if this is a publicly available service, there are none. – Bart Friederichs Jan 10 '19 at 08:11
  • @shawn, Could you change the comment to a solution so i can flag it a the solution. – Ronald Werkhoven Jan 10 '19 at 09:48
  • @RonaldWerkhoven I have updated with more details. Glad you agree with me :D – shawn Jan 10 '19 at 09:59
  • maybe some queueing system would help like rabbitmq – Robert Jan 10 '19 at 10:33
  • @RonaldWerkhoven you must still wait for the client to return a response. In general all webhook issuers (like your system) rely that the consumer returns HTTP 200 if not you should consider it undelivered. The best way to do this at scale is to use a queue of some kind (RDBMS or Rabbitmq) and do not remove the item from the queue until you are sure it was consumed. – Borislav Sabev Jan 11 '19 at 08:17

1 Answers1

3

Run a separated process in background to send the request. Even if you use async http request (whatever language you use), you still must wait for the request to be completed before you exit your script/program.

PHP is not Java, every time the PHP script finishes, all the resources will be destroyed, if the async http request hasn't finished, it will be canceled.

You can consider to call "nohup /path/your_script" to do some background tasks.

Hint: PHP opened files are not marked as FD_CLOEXEC, so if you have a long-run background task, you should close the inherited file descriptors first, or there will be resource leaks.

Here are some C codes I used to help to run background tasks in PHP: it closes all inherited file descriptors first, redirect stdout/stderr to /dev/null, then enter background mode (like nohup)

/*
gcc -m32 bgexec.c  -o bgexec
*/
#include <stdio.h>
#include <stdlib.h>
#include <dirent.h>
#include <fcntl.h>
#include <unistd.h>
#include <sys/types.h>
#include <sys/wait.h>

void close_fds()
{
    char buf[256];
    struct dirent *dp;
    snprintf(buf, 255, "/proc/%i/fd/", getpid());
    DIR *dir = opendir(buf);
    while ((dp = readdir(dir)) != NULL) {
        if(dp->d_name[0] && dp->d_name[0] != '.') {
            //printf("fd: %s\n", dp->d_name);
            close(atoi(dp->d_name));
        }
    }
    closedir(dir);
}

int main(int argc, char *argv[])
{
    int pid;
    signal(SIGCLD, SIG_IGN);   // no defunct when no wait();
    if (argc < 2)
        return fprintf(stderr, "No arguments given\n"), 1;

    /* Fork it */
    pid = fork();
    if(pid < 0)
        return fprintf(stderr, "Couldn't fork\n"), 127;

    if (pid == 0) {
        /* Child */
        setsid();
        umask ( 0 ); /* clear file mode creation mask */
        close_fds();

        int fd = open("/dev/null", O_RDWR);
        dup2(0, 1);
        dup2(0, 2);
        signal(SIGHUP, SIG_IGN);   // no hup
        signal(SIGCLD, SIG_DFL);   // keep away from 'exec' returns ECHILD
        /* Execute it */
        execv(argv[1], &argv[1]);
        exit(127);
    }
    return 0;
}
shawn
  • 4,305
  • 1
  • 17
  • 25