internal modifications

This commit is contained in:
Suriya
2026-08-04 20:44:42 +05:30
parent 588f84c344
commit 77a723e047
3 changed files with 89 additions and 0 deletions

View File

@@ -65,6 +65,11 @@ func AssignCRMMiler(bookingID int) {
"booking_id", bookingID, "booking_id", bookingID,
"max_retries", maxRetries, "max_retries", maxRetries,
) )
// Terminal failure — same handoff as the B2C path. Both entry points must
// publish, or failures arriving via the CRM console stay invisible to the
// DispatchAgent.
publishAssignmentFailed(bookingID, reasonNoMilerAvailable)
} }
// tryAssign performs a single attempt: queries Redis GEO, scores candidates, commits. // tryAssign performs a single attempt: queries Redis GEO, scores candidates, commits.

View File

@@ -58,6 +58,11 @@ func AssignCustomerMiler(bookingID int) {
"booking_id", bookingID, "booking_id", bookingID,
"max_retries", maxRetries, "max_retries", maxRetries,
) )
// Terminal failure — hand off to the AI layer's DispatchAgent, which owns
// what happens next (coverage sweep, escalation). Reached only after every
// retry is exhausted, so it fires at most once per booking.
publishAssignmentFailed(bookingID, reasonNoMilerAvailable)
} }
// tryCustomerAssign performs one full attempt: GEO miler search → provider selection → commit. // tryCustomerAssign performs one full attempt: GEO miler search → provider selection → commit.

View File

@@ -0,0 +1,79 @@
package assignment
import (
"encoding/json"
"time"
"doormile/db"
"doormile/models"
"doormile/utils"
)
// assignmentFailedSubject is the JetStream subject the AI layer's DispatchAgent
// binds its durable consumer to. It must be present on the ASSIGNMENTS stream
// before anything publishes here — JetStream drops messages on subjects the
// stream does not cover, silently and with a successful-looking publish.
const assignmentFailedSubject = "booking.assignment_failed"
// Reasons carried on the failure event. Kept coarse on purpose: the consumer
// branches on booking_id and coordinates, and treats reason as diagnostic only.
const (
reasonNoMilerAvailable = "NO_MILER_AVAILABLE"
)
// publishAssignmentFailed emits booking.assignment_failed after auto-assignment
// has genuinely given up on a booking.
//
// Call this only from the terminal branch of an assignment entry point — after
// every retry is exhausted — never from inside a single attempt. The per-attempt
// paths (no eligible candidates, decision-engine escalation) fire up to
// maxRetries times for a booking that may still succeed on a later attempt, and
// publishing there would report failures that never happened.
//
// Mirrors publishAssignment/publishCustomerAssignment: non-fatal, so a NATS
// outage degrades to a log line rather than breaking the assignment goroutine.
func publishAssignmentFailed(bookingID int, reason string) {
if db.Js == nil {
return
}
payload := map[string]interface{}{
"booking_id": bookingID,
"reason": reason,
"failed_at": time.Now().UnixMilli(),
}
// Pickup coordinates drive the consumer's coverage sweep. They aren't in
// scope at the call site, so re-read the booking — one indexed lookup on a
// path that only runs after retries have already been exhausted. If the
// read fails we still publish: the consumer treats missing coordinates as
// "skip the sweep" and degrades safely rather than losing the event.
var booking models.PickupBooking
if err := db.DB.Select("pickuplatitude", "pickuplongitude", "bookingno").
First(&booking, bookingID).Error; err != nil {
utils.Warn("Assignment: could not load booking for failure event; publishing without coordinates",
"booking_id", bookingID, "error", err)
} else {
payload["booking_no"] = booking.Bookingno
if booking.Pickuplatitude != 0 || booking.Pickuplongitude != 0 {
payload["lat"] = booking.Pickuplatitude
payload["lon"] = booking.Pickuplongitude
}
}
data, err := json.Marshal(payload)
if err != nil {
utils.Warn("Assignment: failed to marshal assignment-failed payload",
"booking_id", bookingID, "error", err)
return
}
if _, err := db.Js.Publish(assignmentFailedSubject, data); err != nil {
utils.Warn("Assignment: NATS publish failed for assignment-failed event",
"booking_id", bookingID, "error", err)
return
}
utils.Info("Assignment: published "+assignmentFailedSubject,
"booking_id", bookingID, "reason", reason)
}