mirror of
https://github.com/writefreely/writefreely
synced 2024-11-10 03:24:11 +00:00
Show 503 page on collections under high load
This acknowledges "too many connections" and "max user connections" errors in MySQL and propagates the error up the chain so we can notify the user and return the correct HTTP code.
This commit is contained in:
parent
06054a2cd7
commit
0285a9b0bd
5 changed files with 30 additions and 0 deletions
|
@ -40,3 +40,13 @@ func (db *datastore) isIgnorableError(err error) bool {
|
|||
|
||||
return false
|
||||
}
|
||||
|
||||
func (db *datastore) isHighLoadError(err error) bool {
|
||||
if db.driverName == driverMySQL {
|
||||
if mysqlErr, ok := err.(*mysql.MySQLError); ok {
|
||||
return mysqlErr.Number == mySQLErrMaxUserConns || mysqlErr.Number == mySQLErrTooManyConns
|
||||
}
|
||||
}
|
||||
|
||||
return false
|
||||
}
|
||||
|
|
|
@ -39,6 +39,8 @@ import (
|
|||
const (
|
||||
mySQLErrDuplicateKey = 1062
|
||||
mySQLErrCollationMix = 1267
|
||||
mySQLErrTooManyConns = 1040
|
||||
mySQLErrMaxUserConns = 1203
|
||||
|
||||
driverMySQL = "mysql"
|
||||
driverSQLite = "sqlite3"
|
||||
|
@ -793,6 +795,8 @@ func (db *datastore) GetCollectionBy(condition string, value interface{}) (*Coll
|
|||
switch {
|
||||
case err == sql.ErrNoRows:
|
||||
return nil, impart.HTTPError{http.StatusNotFound, "Collection doesn't exist."}
|
||||
case db.isHighLoadError(err):
|
||||
return nil, ErrUnavailable
|
||||
case err != nil:
|
||||
log.Error("Failed selecting from collections: %v", err)
|
||||
return nil, err
|
||||
|
|
|
@ -37,6 +37,8 @@ var (
|
|||
ErrInternalGeneral = impart.HTTPError{http.StatusInternalServerError, "The humans messed something up. They've been notified."}
|
||||
ErrInternalCookieSession = impart.HTTPError{http.StatusInternalServerError, "Could not get cookie session."}
|
||||
|
||||
ErrUnavailable = impart.HTTPError{http.StatusServiceUnavailable, "Service temporarily unavailable due to high load."}
|
||||
|
||||
ErrCollectionNotFound = impart.HTTPError{http.StatusNotFound, "Collection doesn't exist."}
|
||||
ErrCollectionGone = impart.HTTPError{http.StatusGone, "This blog was unpublished."}
|
||||
ErrCollectionPageNotFound = impart.HTTPError{http.StatusNotFound, "Collection page doesn't exist."}
|
||||
|
|
|
@ -83,6 +83,7 @@ type ErrorPages struct {
|
|||
NotFound *template.Template
|
||||
Gone *template.Template
|
||||
InternalServerError *template.Template
|
||||
UnavailableError *template.Template
|
||||
Blank *template.Template
|
||||
}
|
||||
|
||||
|
@ -94,6 +95,7 @@ func NewHandler(apper Apper) *Handler {
|
|||
NotFound: template.Must(template.New("").Parse("{{define \"base\"}}<html><head><title>404</title></head><body><p>Not found.</p></body></html>{{end}}")),
|
||||
Gone: template.Must(template.New("").Parse("{{define \"base\"}}<html><head><title>410</title></head><body><p>Gone.</p></body></html>{{end}}")),
|
||||
InternalServerError: template.Must(template.New("").Parse("{{define \"base\"}}<html><head><title>500</title></head><body><p>Internal server error.</p></body></html>{{end}}")),
|
||||
UnavailableError: template.Must(template.New("").Parse("{{define \"base\"}}<html><head><title>503</title></head><body><p>Service is temporarily unavailable.</p></body></html>{{end}}")),
|
||||
Blank: template.Must(template.New("").Parse("{{define \"base\"}}<html><head><title>{{.Title}}</title></head><body><p>{{.Content}}</p></body></html>{{end}}")),
|
||||
},
|
||||
sessionStore: apper.App().SessionStore(),
|
||||
|
@ -111,6 +113,7 @@ func NewWFHandler(apper Apper) *Handler {
|
|||
NotFound: pages["404-general.tmpl"],
|
||||
Gone: pages["410.tmpl"],
|
||||
InternalServerError: pages["500.tmpl"],
|
||||
UnavailableError: pages["503.tmpl"],
|
||||
Blank: pages["blank.tmpl"],
|
||||
})
|
||||
return h
|
||||
|
@ -763,6 +766,10 @@ func (h *Handler) handleHTTPError(w http.ResponseWriter, r *http.Request, err er
|
|||
log.Info("handleHTTPErorr internal error render")
|
||||
h.errors.InternalServerError.ExecuteTemplate(w, "base", pageForReq(h.app.App(), r))
|
||||
return
|
||||
} else if err.Status == http.StatusServiceUnavailable {
|
||||
w.WriteHeader(err.Status)
|
||||
h.errors.UnavailableError.ExecuteTemplate(w, "base", pageForReq(h.app.App(), r))
|
||||
return
|
||||
} else if err.Status == http.StatusAccepted {
|
||||
impart.WriteSuccess(w, "", err.Status)
|
||||
return
|
||||
|
|
7
pages/503.tmpl
Normal file
7
pages/503.tmpl
Normal file
|
@ -0,0 +1,7 @@
|
|||
{{define "head"}}<title>Temporarily Unavailable — {{.SiteMetaName}}</title>{{end}}
|
||||
{{define "content"}}
|
||||
<div class="error-page">
|
||||
<p class="msg">The words aren't coming to me. 🗅</p>
|
||||
<p>We couldn't serve this page due to high server load. This should only be temporary.</p>
|
||||
</div>
|
||||
{{end}}
|
Loading…
Reference in a new issue