Skip to content

Commit 6e35977

Browse files
committed
Fix indefinitely stuck FPM status processes
After switching to dedicated status port provided by php-fpm, the fpm exporter seems to be stuck on connecting to the fcgi. Only way to fix it is connect another procces to the same fpm port. This suggest some issues in the php (8.0) itself, but to overcome that let's allow next request to acctually try connect and unlock all stuck processes
1 parent 825881e commit 6e35977

File tree

1 file changed

+53
-24
lines changed

1 file changed

+53
-24
lines changed

phpfpm/phpfpm.go

+53-24
Original file line numberDiff line numberDiff line change
@@ -15,9 +15,11 @@
1515
package phpfpm
1616

1717
import (
18+
"context"
1819
"encoding/json"
1920
"fmt"
20-
"io/ioutil"
21+
"io"
22+
"net/http"
2123
"net/url"
2224
"regexp"
2325
"strconv"
@@ -163,36 +165,63 @@ func (p *Pool) Update() (err error) {
163165

164166
defer fcgi.Close()
165167

166-
env := map[string]string{
167-
"SCRIPT_FILENAME": path,
168-
"SCRIPT_NAME": path,
169-
"SERVER_SOFTWARE": "go / php-fpm_exporter",
170-
"REMOTE_ADDR": "127.0.0.1",
171-
"QUERY_STRING": "json&full",
172-
}
168+
// Process might hang on execution indefinitely there, and block other requests.
169+
// This still allows for goroutine to live forever, if either of the requests will not finish.
170+
done := make(chan *http.Response, 1)
171+
errCh := make(chan error, 1)
172+
ctx, cancel := context.WithTimeout(context.Background(), time.Second*10)
173+
defer cancel()
174+
175+
go func(ctx context.Context, ch chan *http.Response, errCh chan error) {
176+
env := map[string]string{
177+
"SCRIPT_FILENAME": path,
178+
"SCRIPT_NAME": path,
179+
"SERVER_SOFTWARE": "go / php-fpm_exporter",
180+
"REMOTE_ADDR": "127.0.0.1",
181+
"QUERY_STRING": "json&full",
182+
}
173183

174-
resp, err := fcgi.Get(env)
175-
if err != nil {
176-
return p.error(err)
177-
}
184+
res, err := fcgi.Get(env)
185+
if err != nil {
186+
errCh <- p.error(err)
187+
return
188+
}
178189

179-
defer resp.Body.Close()
190+
select {
191+
case <-ctx.Done():
192+
// request is already done, let's just release response resources
193+
res.Body.Close()
194+
default:
195+
//
196+
ch <- res
197+
}
180198

181-
content, err := ioutil.ReadAll(resp.Body)
182-
if err != nil {
183-
return p.error(err)
184-
}
199+
}(ctx, done, errCh)
185200

186-
content = JSONResponseFixer(content)
201+
select {
202+
case err = <-errCh:
203+
return err
204+
case <-ctx.Done():
205+
return ctx.Err()
206+
case resp := <-done:
207+
defer resp.Body.Close()
208+
209+
content, err := io.ReadAll(resp.Body)
210+
if err != nil {
211+
return p.error(err)
212+
}
187213

188-
log.Debugf("Pool[%v]: %v", p.Address, string(content))
214+
content = JSONResponseFixer(content)
189215

190-
if err = json.Unmarshal(content, &p); err != nil {
191-
log.Errorf("Pool[%v]: %v", p.Address, string(content))
192-
return p.error(err)
193-
}
216+
log.Debugf("Pool[%v]: %v", p.Address, string(content))
194217

195-
return nil
218+
if err = json.Unmarshal(content, &p); err != nil {
219+
log.Errorf("Pool[%v]: %v", p.Address, string(content))
220+
return p.error(err)
221+
}
222+
223+
return nil
224+
}
196225
}
197226

198227
func (p *Pool) error(err error) error {

0 commit comments

Comments
 (0)