Skip to content

git-fcgi: add buffering proxy to quickly read from fcgi - #2

Merged
shankerwangmiao merged 1 commit into
masterfrom
pr-bufferproxy
Mar 16, 2026
Merged

shankerwangmiao merged 1 commit into
masterfrom
pr-bufferproxy

Conversation

@shankerwangmiao

Copy link
Copy Markdown
Member

with a buffer in memory or on a local storage, to prevent cgi processes from waiting for network IO.

This comment was marked as outdated.

This comment was marked as outdated.

This comment was marked as outdated.

This comment was marked as outdated.

with a buffer in memory or on a local storage, to prevent cgi processes
from waiting for network IO.

Copilot AI left a comment

Copy link
Copy Markdown

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Pull request overview

Adds a FastCGI buffering proxy in front of fcgiwrap to decouple upstream (CGI) response production from downstream network I/O, aiming to prevent CGI processes from blocking on slow client reads.

Changes:

  • Introduce a new Go binary (buffering-proxy) that proxies connections and buffers upstream→client data in memory and (optionally) on disk.
  • Update cmd.sh to run the buffering proxy on :5000 and switch spawn-fcgi to a Unix socket upstream (/tmp/fcgi.sock).
  • Update the Docker build to compile and ship the new buffering-proxy binary.

Reviewed changes

Copilot reviewed 3 out of 3 changed files in this pull request and generated 7 comments.

File Description
git-fcgi/cmd.sh Starts buffering proxy and changes fcgiwrap to listen on a Unix socket instead of TCP port 5000.
git-fcgi/buffering-proxy.go New buffering proxy implementation with CLI flags and disk spillover support.
git-fcgi/Dockerfile Builds and copies the new buffering-proxy binary into the runtime image.

💡 Add Copilot custom instructions for smarter, more guided reviews. Learn how to get started.

You can also share your feedback on Copilot code review. Take the survey.

Comment on lines +220 to +251
} else {
tmpFile, err := os.CreateTemp(cfg.onDiskBufferPath, "buffer-*")
if err != nil {
fmt.Printf("Error creating temp file for disk buffer: %v\n", err)
close(channel)
upstreamConn.CloseRead()
break
}
err = os.Remove(tmpFile.Name())
if err != nil {
fmt.Printf("Error removing temp file after creation: %v\n", err)
tmpFile.Close()
close(channel)
upstreamConn.CloseRead()
break
}
var n int64
n, readErr = io.CopyN(tmpFile, upstreamConn, int64(cfg.onDiskBufferUnitSize))
_, err = tmpFile.Seek(0, io.SeekStart)
if err != nil {
fmt.Printf("Error seeking to start of temp file: %v\n", err)
tmpFile.Close()
close(channel)
upstreamConn.CloseRead()
break
}
if n > 0 {
channel <- Buffer{diskBuf: tmpFile}
} else {
tmpFile.Close()
}
}
Comment thread git-fcgi/cmd.sh
Comment on lines 9 to +18
(
while true; do
/go-queue --queue-size "${QUEUE_SIZE}" --port-number 8888
done
)&
exec /usr/bin/spawn-fcgi -u www-data -g www-data -p 5000 -n -- /usr/bin/multiwatch -f ${THREADS} -- /usr/sbin/fcgiwrap
(
while true; do
/buffering-proxy --listen ":5000" --max-buffer-size "${MAX_BUFFER_SIZE}" --on-disk-buffer-path "${BUFFER_PATH}" --upstream "unix:/tmp/fcgi.sock"
done
)&
Comment thread git-fcgi/cmd.sh
/buffering-proxy --listen ":5000" --max-buffer-size "${MAX_BUFFER_SIZE}" --on-disk-buffer-path "${BUFFER_PATH}" --upstream "unix:/tmp/fcgi.sock"
done
)&
exec /usr/bin/spawn-fcgi -u www-data -g www-data -s /tmp/fcgi.sock -n -- /usr/bin/multiwatch -f "${THREADS}" -- /usr/sbin/fcgiwrap
value, err := strconv.ParseUint(val, 10, 64)
if err != nil {
return fmt.Errorf("invalid number format: %v", err)
}
Comment on lines +79 to +88
fmt.Fprintln(os.Stderr, "invalid value for --buffer-unit-size: must be greater than zero")
os.Exit(2)
}
if onDiskBufferUnitSize == 0 {
fmt.Fprintln(os.Stderr, "invalid value for --on-disk-buffer-unit-size: must be greater than zero")
os.Exit(2)
}
if *maxResponseDeadline <= 0 {
fmt.Fprintln(os.Stderr, "invalid value for --max-deadline: must be greater than zero")
os.Exit(2)
}
upstreamConn, ok := _uc.(StreamConn)
if !ok {
fmt.Printf("Failed to cast upstream connection to TCPConn\n")
Comment on lines +154 to +156
go func() { //Downloading data from upstream to client, with buffering
channel := make(chan Buffer, int(cfg.maxBuffers))
go func() { // Sender
@shankerwangmiao
shankerwangmiao merged commit 27bdf9b into master Mar 16, 2026
9 of 12 checks passed
@shankerwangmiao
shankerwangmiao deleted the pr-bufferproxy branch March 16, 2026 17:50
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

None yet

Projects

None yet

Development

Successfully merging this pull request may close these issues.

2 participants