Browse Source

Enhancement in timeout logging

Now logging a python traceback
Yann Weber 5 years ago
parent
commit
fe56265ecd
4 changed files with 49 additions and 4 deletions
  1. 10
    0
      include/python_pyfcgi.h
  2. 12
    0
      src/python_pyfcgi.c
  3. 26
    3
      src/pyworker.c
  4. 1
    1
      src/responder.c

+ 10
- 0
include/python_pyfcgi.h View File

@@ -45,6 +45,7 @@
45 45
 #include "logger.h"
46 46
 #include "python_ioin.h"
47 47
 
48
+#define LIBPYFCGI_TIMEOUT_HEADERS "Content-Type: text/plain\r\nStatus: 504 Gateway Timeout\r\n\r\n"
48 49
 #define LIBPYFCGI_DEFAULT_HEADERS "Content-Type: text/html\r\nStatus: %s\r\n\r\n"
49 50
 #define LIBPYFCGI_DEFAULT_STATUS "200 OK"
50 51
 #define LIBPYFCGI_DEFAULT_CTYPE "Content-Type: text/html\r\n"
@@ -114,6 +115,15 @@ void libpyfcgi_send_headers();
114 115
  */
115 116
 PyObject* _pyfcgi_write_body(PyObject *body_data);
116 117
 
118
+/**@brief Called by the SIGALRM sighandler @ref worker_sigalrmhandler()
119
+ *
120
+ * If no headers sent send a timeout header.
121
+ *
122
+ * Attempt to generate a python exception and to log exception before
123
+ * exiting.
124
+ */
125
+void libpyfcgi_timeout();
126
+
117 127
 /* Defining Python module */
118 128
 
119 129
 /**@brief Public module initialisation function

+ 12
- 0
src/python_pyfcgi.c View File

@@ -530,3 +530,15 @@ err_clean:
530 530
 	if(iter) { Py_DECREF(iter); }
531 531
 	Py_RETURN_NONE;
532 532
 }
533
+
534
+void libpyfcgi_timeout()
535
+{
536
+
537
+	if(!libpyfcgi.headers_sent)
538
+	{
539
+		FCGX_PutStr(LIBPYFCGI_TIMEOUT_HEADERS,
540
+			sizeof(LIBPYFCGI_TIMEOUT_HEADERS),
541
+			libpyfcgi.out);
542
+	}
543
+}
544
+

+ 26
- 3
src/pyworker.c View File

@@ -20,6 +20,7 @@
20 20
 #include "pyworker.h"
21 21
 
22 22
 
23
+static short _wtimeout;
23 24
 /**@brief 1 if worker idle else 0 */
24 25
 static short _worker_idle;
25 26
 /**@brief Indicate that a worker is idle */
@@ -83,6 +84,7 @@ int work333(int wrk_id)
83 84
 		worker_set_busy();
84 85
 		count++;
85 86
 		environ = update_pyenv(py_osmod, envp);
87
+		_wtimeout = 0;
86 88
 
87 89
 		libpyfcgi_clean_response();
88 90
 		libpyfcgi.out = out_stream;
@@ -94,7 +96,19 @@ int work333(int wrk_id)
94 96
 		{
95 97
 			Py_INCREF(entry_ret);
96 98
 		}
97
-
99
+		
100
+		if(_wtimeout)
101
+		{
102
+			PyObject *type, *exc, *tb, *tmp;
103
+			// Changing exception to a TimeoutError, but keeping
104
+			// the traceback to display
105
+			PyErr_Fetch(&type, &exc, &tb);
106
+			PyErr_SetString(PyExc_TimeoutError, "Request timeout");
107
+			PyErr_Fetch(&type, &exc, &tmp);
108
+			PyErr_Restore(type, exc, tb);
109
+			log_expt(LOG_ERR);
110
+			libpyfcgi_timeout(); // Sending headers if possible
111
+		}
98 112
 		if(PyErr_Occurred())
99 113
 		{
100 114
 			pyfcgi_log(LOG_ERR, "PEP333 entrypoint function triggered an exception");
@@ -132,6 +146,10 @@ int work333(int wrk_id)
132 146
 			stop.tv_sec -= 1;
133 147
 		}
134 148
 		pyfcgi_wd_pause();
149
+		if(_wtimeout)
150
+		{
151
+			exit(PYFCGI_TIMEOUT);
152
+		}
135 153
 		pyfcgi_log(LOG_DEBUG, "Worker[%d] request %d END [OK] %lu bytes in %ld.%06lds",
136 154
 			wrk_id, count, libpyfcgi.rep_sz, stop.tv_sec, stop.tv_usec);
137 155
 
@@ -625,7 +643,12 @@ void worker_sighandler(int signum)
625 643
 
626 644
 void worker_sigalrmhandler(int signum)
627 645
 {
628
-	//pyfcgi_log(LOG_WARNING, "Timeout, exiting...");
646
+	_wtimeout = 1;
647
+	if(!_worker_idle)
648
+	{
649
+		// Call PyErr_Interrupt() in order to stop python
650
+		PyErr_SetInterrupt();
651
+	}
629 652
 	worker_set_busy();
630
-	exit(PYFCGI_TIMEOUT);
653
+	return;
631 654
 }

+ 1
- 1
src/responder.c View File

@@ -202,7 +202,7 @@ int responder_loop()
202 202
 				busy_start = time(NULL);
203 203
 			}
204 204
 			else if(time(NULL) - busy_start > 0 &&
205
-				wanted_n <= PyFCGI_conf.max_wrk)
205
+				wanted_n < PyFCGI_conf.max_wrk)
206 206
 			{
207 207
 				pyfcgi_log( LOG_DEBUG,
208 208
 					"All workers busy, spawning a new one");

Loading…
Cancel
Save