Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

WIP: Implement systemd-notify protocol #21140

Closed
wants to merge 1 commit into from

Conversation

clarfonthey
Copy link
Contributor

@clarfonthey clarfonthey commented Sep 11, 2022

Right now, the systemd service will mark gitea as started immediately after the process is started, even though there are multiple time-consuming steps that might be run before the server is actually up. This implements systemd's notify protocol to indicate when the server is ready to receive requests, and when it's shutting down. This is particularly useful for socket activation, since systemd will hold the traffic in a queue until the process is ready, to avoid dropping requests.

Since notifications are done via an environment variable, this has no effect on systems where this environment variable is not present.

Marking as a draft since I'm currently developing from a pinebook and it's a bit too slow for me to test the changes for now, but I wanted to put up the code as a proof of concept and will mark it ready once I test it.

func (srv *Server) Notify(msg NotifyMsg) {
notifySocket := Os.Getenv("NOTIFY_SOCKET")
if notifySocket == "" {
log.Debug("no NOTIFY_SOCKET given")
Copy link
Member

Choose a reason for hiding this comment

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

Suggested change
log.Debug("no NOTIFY_SOCKET given")
log.Debug("no NOTIFY_SOCKET given, Gitea is probably not deployed using systemd")

Comment on lines +155 to +169
type NotifyMsg int8

const {
ReadyMsg NotifyMsg = iota
StoppingMsg
}

func (msg *NotifyMsg) Bytes() []byte {
switch msg {
case ReadyMsg:
return []byte("READY=1")
case StoppingMsg:
return []byte("STOPPING=1")
}
}
Copy link
Member

Choose a reason for hiding this comment

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

As far as I can see, only the bytes are needed in your implementation.
So, why not skip the ints and make them strings/ byte arrays immediately?

Copy link
Contributor Author

Choose a reason for hiding this comment

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

I was trying to pretend that golang has abstract data types but I probably should just give up and use byte strings.

}
}

// systemd notify protocol
Copy link
Member

@delvh delvh Sep 11, 2022

Choose a reason for hiding this comment

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

Suggested change
// systemd notify protocol
// Notify notifies systemd (if present) about the given startup status of Gitea

Comment on lines +186 to +198
log.Warn("failed to unsetenv NOTIFY_SOCKET: %v", err)
return
}

conn, err := net.DialUnix(socketAddr.Net, nil, socketAddr)
if err != nil {
log.Warn("failed to dial NOTIFY_SOCKET: %v", err)
return
}
defer conn.close()

if _, err = conn.Write(msg.Bytes()) {
log.Warn("failed to notify NOTIFY_SOCKET: %v", err)
Copy link
Member

Choose a reason for hiding this comment

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

Suggested change
log.Warn("failed to unsetenv NOTIFY_SOCKET: %v", err)
return
}
conn, err := net.DialUnix(socketAddr.Net, nil, socketAddr)
if err != nil {
log.Warn("failed to dial NOTIFY_SOCKET: %v", err)
return
}
defer conn.close()
if _, err = conn.Write(msg.Bytes()) {
log.Warn("failed to notify NOTIFY_SOCKET: %v", err)
SystemdNotificationImpossible("unsetenv", err)
return
}
conn, err := net.DialUnix(socketAddr.Net, nil, socketAddr)
if err != nil {
SystemdNotificationImpossible("dial", err)
return
}
defer conn.close()
if _, err = conn.Write(msg.Bytes()) {
SystemdNotificationImpossible("notify", err)

return []byte("STOPPING=1")
}
}

Copy link
Member

@delvh delvh Sep 11, 2022

Choose a reason for hiding this comment

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

Suggested change
func SystemdNotificationImpossible(action string, err error) {
log.Warn("Failed to %s NOTIFY_SOCKET (%v). Systemd might show some weird states: %v", action, os.Getenv("NOTIFY_SOCKET"), err)
}

@GiteaBot GiteaBot added the lgtm/need 2 This PR needs two approvals by maintainers to be considered for merging. label Sep 11, 2022
@zeripath
Copy link
Contributor

So I think this is in the wrong place. The Notify function will belong in manager_unix.go and manager.go not server.go.

The functions and structs in server.go are called for multiple connections that gitea uses. The manager is the controller and it is that which should be notifying things.

zeripath pushed a commit to zeripath/gitea that referenced this pull request Sep 12, 2022
This PR adds support for the systemd notify protocol. Several status
messagess are provided. We should likely add a common notify/status
message for graceful.

Replaces go-gitea#21140

Signed-off-by: Andrew Thornton <art27@cantab.net>
@clarfonthey
Copy link
Contributor Author

clarfonthey commented Sep 17, 2022

Will close this in favour of @zeripath's PR since he's putting the work into this.

@go-gitea go-gitea locked and limited conversation to collaborators May 3, 2023
Sign up for free to subscribe to this conversation on GitHub. Already have an account? Sign in.
Labels
lgtm/need 2 This PR needs two approvals by maintainers to be considered for merging.
Projects
None yet
Development

Successfully merging this pull request may close these issues.

None yet

4 participants