Refuse an event heard during a reload instead of panicking, and judge a bundle by its entrypoint alone (issue 1945, review)
An event a module's consumer heard after the module was dropped for a reload read a deleted entry and panicked node-tools, taking every tool on the machine down. The handler now refuses an event of a consumer that is no longer the module's, and a stopped hearing hands nothing on and offers the event again at once. A bundle that writes beside itself (a cache, a socket) loaded itself again after every quiet spell, because the signature took in every file in its directory. A delivery puts every file in place anew, so the entrypoint alone tells a new build. The watch also looks once as it begins, so a bundle that came between its load and the watch is not missed. Tests: 1945/AC23 and AC24 in internal/runtime/reload_test.go, and a stopped hearing in internal/bus/hearing_stopped_test.go.
This commit is contained in:
@@ -87,8 +87,9 @@ func (w *bundleWatch) arm() {
|
||||
func (w *bundleWatch) loop() {
|
||||
defer close(w.done)
|
||||
buf := make([]byte, 64*1024)
|
||||
pending := false
|
||||
var quietAt time.Time
|
||||
// Looked at once as the watch begins: a bundle that came between its load and the watch is not missed.
|
||||
pending := true
|
||||
quietAt := time.Now()
|
||||
for {
|
||||
timeout := -1
|
||||
if pending {
|
||||
@@ -149,8 +150,10 @@ func (w *bundleWatch) drain(buf []byte) {
|
||||
}
|
||||
|
||||
// signatureOf is what the runtime compares to tell that an entrypoint changed: the file's identity,
|
||||
// mode, size and times, and those of every file beside it (a launcher starts what its build wrote
|
||||
// next to it). "" is a file that does not exist.
|
||||
// mode, size and times; "" is a file that does not exist. Only the entrypoint: a delivery puts every file
|
||||
// of a bundle in place anew (a directory swapped in, or each file renamed in), so the entrypoint is new
|
||||
// whenever its build is, while a file beside it may be one the bundle itself writes (a cache, a socket),
|
||||
// which would load it again after every quiet spell, and modules sharing a directory each other.
|
||||
func signatureOf(path string) string {
|
||||
info, err := os.Stat(path)
|
||||
if errors.Is(err, fs.ErrNotExist) {
|
||||
@@ -159,15 +162,7 @@ func signatureOf(path string) string {
|
||||
if err != nil {
|
||||
return "unreadable: " + err.Error()
|
||||
}
|
||||
sig := statSignature(info)
|
||||
if entries, err := os.ReadDir(filepath.Dir(path)); err == nil {
|
||||
for _, e := range entries {
|
||||
if i, err := e.Info(); err == nil {
|
||||
sig += "|" + e.Name() + " " + statSignature(i)
|
||||
}
|
||||
}
|
||||
}
|
||||
return sig
|
||||
return statSignature(info)
|
||||
}
|
||||
|
||||
func statSignature(info fs.FileInfo) string {
|
||||
|
||||
Reference in New Issue
Block a user