You are viewing a plain text version of this content. The canonical link for it is here.
Posted to cvs@httpd.apache.org by tr...@apache.org on 2002/02/01 23:08:34 UTC

cvs commit: httpd-2.0/modules/generators mod_cgid.c

trawick     02/02/01 14:08:34

  Modified:    .        CHANGES
               modules/generators mod_cgid.c
  Log:
  mod_cgid: Add retry logic for when the daemon can't fork fast
  enough to keep up with new requests.  Start using
  HTTP_SERVER_UNAVAILABLE instead of HTTP_INTERNAL_SERVER_ERROR
  when we can't talk to the daemon.
  
  Revision  Changes    Path
  1.560     +5 -0      httpd-2.0/CHANGES
  
  Index: CHANGES
  ===================================================================
  RCS file: /home/cvs/httpd-2.0/CHANGES,v
  retrieving revision 1.559
  retrieving revision 1.560
  diff -u -r1.559 -r1.560
  --- CHANGES	1 Feb 2002 19:25:13 -0000	1.559
  +++ CHANGES	1 Feb 2002 22:08:33 -0000	1.560
  @@ -1,5 +1,10 @@
   Changes with Apache 2.0.32-dev
   
  +  *) mod_cgid: Add retry logic for when the daemon can't fork fast
  +     enough to keep up with new requests.  Start using 
  +     HTTP_SERVER_UNAVAILABLE instead of HTTP_INTERNAL_SERVER_ERROR
  +     when we can't talk to the daemon.  [Jeff Trawick]
  +
     *) apxs: LTFLAGS envvar can override default libtool options.  Try
        "LTFLAGS=' ' apxs -c mod_foo.c" to see what libtool does under
        the covers.  [Jeff Trawick]
  
  
  
  1.112     +73 -34    httpd-2.0/modules/generators/mod_cgid.c
  
  Index: mod_cgid.c
  ===================================================================
  RCS file: /home/cvs/httpd-2.0/modules/generators/mod_cgid.c,v
  retrieving revision 1.111
  retrieving revision 1.112
  diff -u -r1.111 -r1.112
  --- mod_cgid.c	28 Jan 2002 18:30:07 -0000	1.111
  +++ mod_cgid.c	1 Feb 2002 22:08:34 -0000	1.112
  @@ -127,6 +127,7 @@
   
   static apr_pool_t *pcgi; 
   static int total_modules = 0;
  +static pid_t daemon_pid;
   
   /* KLUDGE --- for back-combatibility, we don't have to check Execcgid 
    * in ScriptAliased directories, which means we need to know if this 
  @@ -160,6 +161,19 @@
   #define DEFAULT_CGID_LISTENBACKLOG 100
   #endif
   
  +/* DEFAULT_CONNECT_ATTEMPTS controls how many times we'll try to connect
  + * to the cgi daemon from the thread/process handling the cgi request.
  + * Generally we want to retry when we get ECONNREFUSED since it is
  + * probably because the listen queue is full.  We need to try harder so
  + * the client doesn't see it as a 503 error.
  + *
  + * Set this to 0 to continually retry until the connect works or Apache
  + * terminates.
  + */
  +#ifndef DEFAULT_CONNECT_ATTEMPTS
  +#define DEFAULT_CONNECT_ATTEMPTS  15
  +#endif
  +
   typedef struct { 
       const char *sockname;
       const char *logname; 
  @@ -596,7 +610,6 @@
   static int cgid_init(apr_pool_t *p, apr_pool_t *plog, apr_pool_t *ptemp, 
                         server_rec *main_server) 
   { 
  -    pid_t pid; 
       apr_proc_t *procnew;
       void *data;
       int first_time = 0;
  @@ -615,18 +628,18 @@
           for (m = ap_preloaded_modules; *m != NULL; m++)
               total_modules++;
   
  -        if ((pid = fork()) < 0) {
  +        if ((daemon_pid = fork()) < 0) {
               ap_log_error(APLOG_MARK, APLOG_ERR, errno, main_server, 
                            "Couldn't spawn cgid daemon process"); 
               /* XXX should we return a failure here ? */
           }
  -        else if (pid == 0) {
  +        else if (daemon_pid == 0) {
               apr_pool_create(&pcgi, p); 
               cgid_server(main_server);
               exit(-1);
           } 
           procnew = apr_pcalloc(p, sizeof(*procnew));
  -        procnew->pid = pid;
  +        procnew->pid = daemon_pid;
           procnew->err = procnew->in = procnew->out = NULL;
           apr_pool_note_subprocess(p, procnew, kill_after_timeout);
   #if APR_HAS_OTHER_CHILD
  @@ -850,6 +863,58 @@
       return close(fd);
   }
   
  +static int connect_to_daemon(int *sdptr, request_rec *r,
  +                             cgid_server_conf *conf)
  +{
  +    struct sockaddr_un unix_addr;
  +    int sd;
  +    int connect_tries;
  +    apr_interval_time_t sliding_timer;
  +
  +    memset(&unix_addr, 0, sizeof(unix_addr));
  +    unix_addr.sun_family = AF_UNIX;
  +    strcpy(unix_addr.sun_path, conf->sockname);
  +
  +    connect_tries = 0;
  +    sliding_timer = 100000; /* 100 milliseconds */
  +    while (1) {
  +        ++connect_tries;
  +        if ((sd = socket(AF_UNIX, SOCK_STREAM, 0)) < 0) {
  +            return log_scripterror(r, conf, HTTP_INTERNAL_SERVER_ERROR, errno, 
  +                                   "unable to create socket to cgi daemon");
  +        }
  +        if (connect(sd, (struct sockaddr *)&unix_addr, sizeof(unix_addr)) < 0) {
  +            if (errno == ECONNREFUSED && connect_tries < DEFAULT_CONNECT_ATTEMPTS) {
  +                ap_log_rerror(APLOG_MARK, APLOG_DEBUG, errno, r,
  +                              "connect #%d to cgi daemon failed, sleeping before retry",
  +                              connect_tries);
  +                close(sd);
  +                apr_sleep(sliding_timer);
  +                if (sliding_timer < 2 * APR_USEC_PER_SEC) {
  +                    sliding_timer *= 2;
  +                }
  +            }
  +            else {
  +                close(sd);
  +                return log_scripterror(r, conf, HTTP_SERVICE_UNAVAILABLE, errno, 
  +                                       "unable to connect to cgi daemon after multiple tries");
  +            }
  +        }
  +        else {
  +            apr_pool_cleanup_register(r->pool, (void *)sd, close_unix_socket,
  +                                      apr_pool_cleanup_null);
  +            break; /* we got connected! */
  +        }
  +        /* gotta try again, but make sure the cgid daemon is still around */
  +        if (kill(daemon_pid, 0) != 0) {
  +            return log_scripterror(r, conf, HTTP_SERVICE_UNAVAILABLE, errno,
  +                                   "cgid daemon is gone; is Apache terminating?");
  +        }
  +    }
  +    *sdptr = sd;
  +    return OK;
  +}
  +
   /**************************************************************** 
    * 
    * Actual cgid handling... 
  @@ -865,7 +930,6 @@
       int is_included;
       int sd;
       char **env; 
  -    struct sockaddr_un unix_addr;
       apr_file_t *tempsock;
       apr_size_t nbytes;
   
  @@ -928,21 +992,9 @@
       ap_add_cgi_vars(r); 
       env = ap_create_environment(r->pool, r->subprocess_env); 
   
  -    if ((sd = socket(AF_UNIX, SOCK_STREAM, 0)) < 0) {
  -            return log_scripterror(r, conf, HTTP_INTERNAL_SERVER_ERROR, errno, 
  -                                   "unable to create socket to cgi daemon");
  +    if ((retval = connect_to_daemon(&sd, r, conf)) != OK) {
  +        return retval;
       }
  -    apr_pool_cleanup_register(r->pool, (void *)sd, close_unix_socket,
  -                              apr_pool_cleanup_null);
  -    
  -    memset(&unix_addr, 0, sizeof(unix_addr));
  -    unix_addr.sun_family = AF_UNIX;
  -    strcpy(unix_addr.sun_path, conf->sockname);
  -
  -    if (connect(sd, (struct sockaddr *)&unix_addr, sizeof(unix_addr)) < 0) {
  -            return log_scripterror(r, conf, HTTP_INTERNAL_SERVER_ERROR, errno, 
  -                                   "unable to connect to cgi daemon");
  -    } 
   
       send_req(sd, r, argv0, env, CGI_REQ); 
   
  @@ -1196,7 +1248,6 @@
       int retval;
       apr_bucket_brigade *bcgi;
       apr_bucket *b;
  -    struct sockaddr_un unix_addr;
       apr_file_t *tempsock = NULL;
       cgid_server_conf *conf = ap_get_module_config(r->server->module_config,
                                                     &cgid_module); 
  @@ -1204,21 +1255,9 @@
       add_ssi_vars(r, f->next);
       env = ap_create_environment(r->pool, r->subprocess_env);
   
  -    if ((sd = socket(AF_UNIX, SOCK_STREAM, 0)) < 0) {
  -            return log_scripterror(r, conf, HTTP_INTERNAL_SERVER_ERROR, 0, 
  -                                   "unable to create socket to cgi daemon");
  +    if ((retval = connect_to_daemon(&sd, r, conf)) != OK) {
  +        return retval;
       }
  -    apr_pool_cleanup_register(r->pool, (void *)sd, close_unix_socket,
  -                              apr_pool_cleanup_null);
  -    
  -    memset(&unix_addr, 0, sizeof(unix_addr));
  -    unix_addr.sun_family = AF_UNIX;
  -    strcpy(unix_addr.sun_path, conf->sockname);
  -
  -    if (connect(sd, (struct sockaddr *)&unix_addr, sizeof(unix_addr)) < 0) {
  -            return log_scripterror(r, conf, HTTP_INTERNAL_SERVER_ERROR, 0, 
  -                                   "unable to connect to cgi daemon");
  -    } 
   
       SPLIT_AND_PASS_PRETAG_BUCKETS(*bb, ctx, f->next, rc);
       if (rc != APR_SUCCESS) {