Let a module read its own streams back by a batch direct get, as it reads its log, so its tools can answer what the stream holds (a build step's whole failure output)
This commit is contained in:
@@ -221,49 +221,17 @@ func (c *Conn) LogRead(module, name string, from uint64, keys string, limit int)
|
||||
if from == 0 {
|
||||
from = 1
|
||||
}
|
||||
req, _ := json.Marshal(map[string]any{"seq": from, "next_by_subj": filter, "batch": limit, "max_bytes": LogPageBytes})
|
||||
inbox := c.nc.NewInbox()
|
||||
sub, err := c.nc.SubscribeSync(inbox)
|
||||
msgs, next, err := c.directBatch(l.Stream, filter, from, limit, name, func() error { return notOnTheBus(l) })
|
||||
if err != nil {
|
||||
return nil, err
|
||||
}
|
||||
defer func() { _ = sub.Unsubscribe() }()
|
||||
if err := c.nc.PublishRequest("$JS.API.DIRECT.GET."+l.Stream, inbox, req); err != nil {
|
||||
return nil, err
|
||||
}
|
||||
page := &LogPage{Entries: []LogEntry{}}
|
||||
deadline := time.Now().Add(StateTimeout)
|
||||
for done := false; !done; {
|
||||
msg, err := sub.NextMsg(time.Until(deadline))
|
||||
page := &LogPage{Entries: []LogEntry{}, Next: next}
|
||||
for _, msg := range msgs {
|
||||
e, err := logEntryOf(l, msg)
|
||||
if err != nil {
|
||||
if errors.Is(err, nats.ErrNoResponders) {
|
||||
return nil, notOnTheBus(l)
|
||||
}
|
||||
if errors.Is(err, nats.ErrTimeout) {
|
||||
return nil, fmt.Errorf("the read of %s did not end in %s", name, StateTimeout)
|
||||
}
|
||||
return nil, err
|
||||
}
|
||||
switch status := msg.Header.Get("Status"); status {
|
||||
case "":
|
||||
e, err := logEntryOf(l, msg)
|
||||
if err != nil {
|
||||
return nil, err
|
||||
}
|
||||
page.Entries = append(page.Entries, *e)
|
||||
case "204": // the end of the batch: what is still pending after the last entry sent
|
||||
pending, _ := strconv.ParseUint(msg.Header.Get("Nats-Num-Pending"), 10, 64)
|
||||
if pending > 0 && len(page.Entries) > 0 {
|
||||
page.Next = page.Entries[len(page.Entries)-1].Sequence + 1
|
||||
}
|
||||
done = true
|
||||
case "404": // nothing from that sequence on
|
||||
done = true
|
||||
case "503":
|
||||
return nil, notOnTheBus(l)
|
||||
default:
|
||||
return nil, fmt.Errorf("the read of %s was refused by the bus: %s %s", name, status, msg.Header.Get("Description"))
|
||||
}
|
||||
page.Entries = append(page.Entries, *e)
|
||||
}
|
||||
info, err := c.logInfo(l)
|
||||
if err != nil {
|
||||
@@ -273,6 +241,58 @@ func (c *Conn) LogRead(module, name string, from uint64, keys string, limit int)
|
||||
return page, nil
|
||||
}
|
||||
|
||||
// directBatch is the messages of a stream from a sequence on, on the subjects matching filter, at most limit and about
|
||||
// LogPageBytes, by one batch direct get (NATS 2.11), and the sequence to read on from, 0 when nothing follows. name is
|
||||
// what is read, for its errors; missing is the error of a stream that is not on the bus.
|
||||
func (c *Conn) directBatch(stream, filter string, from uint64, limit int, name string, missing func() error) ([]*nats.Msg, uint64, error) {
|
||||
if from == 0 {
|
||||
from = 1
|
||||
}
|
||||
req, _ := json.Marshal(map[string]any{"seq": from, "next_by_subj": filter, "batch": limit, "max_bytes": LogPageBytes})
|
||||
inbox := c.nc.NewInbox()
|
||||
sub, err := c.nc.SubscribeSync(inbox)
|
||||
if err != nil {
|
||||
return nil, 0, err
|
||||
}
|
||||
defer func() { _ = sub.Unsubscribe() }()
|
||||
if err := c.nc.PublishRequest("$JS.API.DIRECT.GET."+stream, inbox, req); err != nil {
|
||||
return nil, 0, err
|
||||
}
|
||||
var msgs []*nats.Msg
|
||||
var next uint64
|
||||
deadline := time.Now().Add(StateTimeout)
|
||||
for done := false; !done; {
|
||||
msg, err := sub.NextMsg(time.Until(deadline))
|
||||
if err != nil {
|
||||
if errors.Is(err, nats.ErrNoResponders) {
|
||||
return nil, 0, missing()
|
||||
}
|
||||
if errors.Is(err, nats.ErrTimeout) {
|
||||
return nil, 0, fmt.Errorf("the read of %s did not end in %s", name, StateTimeout)
|
||||
}
|
||||
return nil, 0, err
|
||||
}
|
||||
switch status := msg.Header.Get("Status"); status {
|
||||
case "":
|
||||
msgs = append(msgs, msg)
|
||||
case "204": // the end of the batch: what is still pending after the last message sent
|
||||
pending, _ := strconv.ParseUint(msg.Header.Get("Nats-Num-Pending"), 10, 64)
|
||||
if pending > 0 && len(msgs) > 0 {
|
||||
last, _ := strconv.ParseUint(msgs[len(msgs)-1].Header.Get("Nats-Sequence"), 10, 64)
|
||||
next = last + 1
|
||||
}
|
||||
done = true
|
||||
case "404": // nothing from that sequence on
|
||||
done = true
|
||||
case "503":
|
||||
return nil, 0, missing()
|
||||
default:
|
||||
return nil, 0, fmt.Errorf("the read of %s was refused by the bus: %s %s", name, status, msg.Header.Get("Description"))
|
||||
}
|
||||
}
|
||||
return msgs, next, nil
|
||||
}
|
||||
|
||||
// LogLast is a key's last entry, or nil when it has none.
|
||||
func (c *Conn) LogLast(module, name, key string) (*LogEntry, error) {
|
||||
l, err := c.issuedLog(module, name)
|
||||
|
||||
Reference in New Issue
Block a user