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

consider setting up a fallback mechanism to serve existing versions of Go modules in case of provider outage #38

Open
dmitshur opened this issue Feb 13, 2020 · 1 comment

Comments

@dmitshur
Copy link
Member

If the server that is hosting the https://dmitri.shuralyov.com website is unavailable due to an outage of its current server provider (as has happened recently in #37), it may be worth considering a fallback plan.

It can be a quick-to-start second instance, or perhaps a more static page that makes use of the Go module versions already cached by https://proxy.golang.org and serving those instead.

This is the tracking issue to investigate and implement this.

Note that as more and more people update to Go 1.13 or newer, which uses https://proxy.golang.org by default, the benefit from doing this will diminish.

@dmitshur
Copy link
Member Author

or perhaps a more static page that makes use of the Go module versions already cached by https://proxy.golang.org and serving those instead.

I've tested out the following simple approach locally (by adding a dmitri.shuralyov.com→127.0.0.1 override to /etc/hosts and using @FiloSottile's mkcert to serve the replacement site over https), and confirmed that it would work as I expected:

// Play with a fallback solution for serving dmitri.shuralyov.com modules,
// when the main dmitri.shuralyov.com server is completely unavailable.
//
// The fallback solution is to host a very simple site that just temporarily
// points to the modules that have already been mirrored by proxy.golang.org.
package main

import (
	"log"
	"net/http"
	"net/url"
	"os"

	"github.com/shurcooL/home/httputil"
	"golang.org/x/net/html"
)

func main() {
	err := run()
	if err != nil {
		log.Fatalln(err)
	}
}

func run() error {
	h := httputil.ErrorHandler(nil, func(w http.ResponseWriter, req *http.Request) error {
		if req.URL.RawQuery != "go-get=1" {
			return os.ErrNotExist
		}
		if err := httputil.AllowMethods(req, http.MethodGet); err != nil {
			return err
		}
		w.Header().Set("Content-Type", "text/plain; charset=utf-8")
		err := html.Render(w, &html.Node{
			Type: html.ElementNode, Data: "meta",
			Attr: []html.Attribute{
				{Key: "name", Val: "go-import"},
				{Key: "content", Val: (&url.URL{Path: "dmitri.shuralyov.com" + req.URL.Path}).String() +
					" mod https://proxy.golang.org"},
			},
		})
		return err
	})
	return http.ListenAndServeTLS(":https", "dmitri.shuralyov.com.pem", "dmitri.shuralyov.com-key.pem", h)
}

It's not quite static because it needs to serve multiple paths corresponding to package import paths, not just the root. But still very simple and doesn't need knowledge of what packages/modules exist or not. It just redirects everything, and the module mirror serves only the modules that do exist.

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment
Development

No branches or pull requests

2 participants
@dmitshur and others