W2.7 (format): an event kept last per subject, in a stream of its own
The node-engine's running.<node>.<module> is kept last per subject with no age limit, which the shared events stream cannot say; the reader takes keep last-per-subject. Claude-Session: https://claude.ai/code/session_01JG73KEq4zoDfM9WtYpcQgZ
This commit is contained in:
@@ -122,8 +122,19 @@ type Message struct {
|
||||
// still knows the event. Empty, the subject is the name. A part `<node>` is the node that publishes it, which
|
||||
// the grants part grants a node's account alone (ADR 0363 §2).
|
||||
Subject string `json:"subject,omitempty"`
|
||||
// Keep says how an event is kept when not as the family keeps the seat's others: KeepLastPerSubject, in a stream
|
||||
// of its own named KeptStream, the last message of each subject and no age limit (design 47: the node-engine's
|
||||
// running.<node>.<module>, so the last build of every module on every node stays on the bus however long ago
|
||||
// it was said, and a durable consumer starting from the last message per subject holds them all).
|
||||
Keep string `json:"keep,omitempty"`
|
||||
}
|
||||
|
||||
// KeepLastPerSubject is an event kept last per subject with no age limit, in a stream of its own.
|
||||
const KeepLastPerSubject = "last-per-subject"
|
||||
|
||||
// KeptStream is the stream an event with Keep is kept in: `<seat>.<event>`, as a family is `<seat>.events`.
|
||||
func KeptStream(seat string, m Message) string { return seat + "." + m.Name }
|
||||
|
||||
// SubjectPattern is the event's subject after the seat's event prefix with its parts between angle brackets: the
|
||||
// name itself when the definition gives no subject.
|
||||
func (m Message) SubjectPattern() string {
|
||||
@@ -663,6 +674,14 @@ func checkMessages(field string, ms []Message, whole bool) Problems {
|
||||
ps = append(ps, Problem{where + ".name", fmt.Sprintf("%q twice", m.Name)})
|
||||
}
|
||||
seen[m.Name] = true
|
||||
switch {
|
||||
case m.Keep != "" && field != "events":
|
||||
ps = append(ps, Problem{where + ".keep", "only an event is kept"})
|
||||
case m.Keep != "" && m.Keep != KeepLastPerSubject:
|
||||
ps = append(ps, Problem{where + ".keep", fmt.Sprintf("%q is not %s", m.Keep, KeepLastPerSubject)})
|
||||
case m.Keep != "" && len(m.Parts()) == 0 && !m.ByCaller:
|
||||
ps = append(ps, Problem{where + ".keep", "an event of one subject kept last per subject is one message: give it a subject with parts"})
|
||||
}
|
||||
if m.Subject != "" && field != "events" {
|
||||
ps = append(ps, Problem{where + ".subject", "only an event carries a subject of its own"})
|
||||
} else if why := checkSubject(m); why != "" {
|
||||
|
||||
@@ -63,6 +63,12 @@ func TestADefinitionIsReadStrictlyNamingWhatIsWrong(t *testing.T) {
|
||||
`"name":"running","subject":"running.<node>.<node>"`, 1), "part <node> twice"},
|
||||
{"a subject on an event named by its caller", strings.Replace(whole, `"name":"created"`,
|
||||
`"name":"owed","by-caller":true,"subject":"owed.<number>"`, 1), "carries no subject of its own"},
|
||||
{"an event kept last per subject", strings.Replace(whole, `"name":"created"`,
|
||||
`"name":"running","subject":"running.<node>.<module>","keep":"last-per-subject"`, 1), ""},
|
||||
{"an event kept otherwise", strings.Replace(whole, `"name":"created"`,
|
||||
`"name":"running","subject":"running.<node>","keep":"forever"`, 1), `events[0].keep: "forever" is not last-per-subject`},
|
||||
{"an event of one subject kept last per subject", strings.Replace(whole, `"name":"created"`,
|
||||
`"name":"running","keep":"last-per-subject"`, 1), "give it a subject with parts"},
|
||||
{"an accept with dotted words", strings.Replace(whole, `"events":`,
|
||||
`"accepts":[{"name":"run.now","body":{}}],"events":`, 1), "accepts[0].name"},
|
||||
{"a verb twice", strings.Replace(listGrain, `]}`, `,{"name":"add"}]}`, 1), `"add" twice`},
|
||||
|
||||
Reference in New Issue
Block a user