Fix monitoring PF project list deadlock
All checks were successful
Build and Deploy / build-and-deploy (push) Successful in 37s

This commit is contained in:
Grendgi
2026-06-05 11:56:47 +03:00
parent 54cc9372af
commit 76975c3c6c

View File

@@ -270,7 +270,7 @@ func (a *App) ListProjects(ctx context.Context, ownerID int64) ([]Project, error
defer rows.Close() defer rows.Close()
items := []Project{} items := []Project{}
for rows.Next() { for rows.Next() {
p, err := a.scanProject(rows, false) p, err := a.scanProject(ctx, rows, false)
if err != nil { if err != nil {
return nil, err return nil, err
} }
@@ -281,7 +281,7 @@ func (a *App) ListProjects(ctx context.Context, ownerID int64) ([]Project, error
func (a *App) ProjectByID(ctx context.Context, ownerID, projectID int64, detail bool) (*Project, error) { func (a *App) ProjectByID(ctx context.Context, ownerID, projectID int64, detail bool) (*Project, error) {
row := a.DB.QueryRowContext(ctx, projectSelect()+` WHERE p.id = ? AND p.owner_id = ?`, projectID, ownerID) row := a.DB.QueryRowContext(ctx, projectSelect()+` WHERE p.id = ? AND p.owner_id = ?`, projectID, ownerID)
p, err := a.scanProject(row, detail) p, err := a.scanProject(ctx, row, detail)
if errors.Is(err, sql.ErrNoRows) { if errors.Is(err, sql.ErrNoRows) {
return nil, ErrNotFound return nil, ErrNotFound
} }
@@ -435,19 +435,25 @@ func projectSelect() string {
(SELECT count(*) FROM competitor_listings l WHERE l.project_id = p.id), (SELECT count(*) FROM competitor_listings l WHERE l.project_id = p.id),
(SELECT count(*) FROM competitor_listings l WHERE l.project_id = p.id AND l.status IN ('ACTIVE','active')), (SELECT count(*) FROM competitor_listings l WHERE l.project_id = p.id AND l.status IN ('ACTIVE','active')),
(SELECT count(*) FROM competitor_listings l WHERE l.project_id = p.id AND l.status IN ('REMOVED','removed')), (SELECT count(*) FROM competitor_listings l WHERE l.project_id = p.id AND l.status IN ('REMOVED','removed')),
(SELECT min(l.current_price) FROM competitor_listings l WHERE l.project_id = p.id AND l.status IN ('ACTIVE','active') AND l.current_price IS NOT NULL) (SELECT min(l.current_price) FROM competitor_listings l WHERE l.project_id = p.id AND l.status IN ('ACTIVE','active') AND l.current_price IS NOT NULL),
FROM projects p` e.id, e.name, e.portal_user_id, e.tg_chat_id, e.tg_username, e.created_at,
(SELECT count(*) FROM projects owner_p WHERE owner_p.owner_id = e.id) AS owner_projects_total
FROM projects p
LEFT JOIN employees e ON e.id = p.owner_id`
} }
func (a *App) scanProject(row rowScanner, detail bool) (*Project, error) { func (a *App) scanProject(ctx context.Context, row rowScanner, detail bool) (*Project, error) {
var p Project var p Project
var deal string var deal string
var price, size, minPrice sql.NullFloat64 var price, size, minPrice sql.NullFloat64
var notes, permit, building, ourURL, created, checked sql.NullString var notes, permit, building, ourURL, created, checked sql.NullString
var bedrooms sql.NullInt64 var bedrooms sql.NullInt64
var ownerID, ownerProjectsTotal sql.NullInt64
var ownerName, ownerPortalID, ownerChatID, ownerUsername, ownerCreated sql.NullString
if err := row.Scan( if err := row.Scan(
&p.ID, &p.Title, &deal, &price, &notes, &permit, &building, &bedrooms, &size, &ourURL, &p.ID, &p.Title, &deal, &price, &notes, &permit, &building, &bedrooms, &size, &ourURL,
&p.OwnerID, &created, &checked, &p.ListingsTotal, &p.ListingsActive, &p.ListingsRemoved, &minPrice, &p.OwnerID, &created, &checked, &p.ListingsTotal, &p.ListingsActive, &p.ListingsRemoved, &minPrice,
&ownerID, &ownerName, &ownerPortalID, &ownerChatID, &ownerUsername, &ownerCreated, &ownerProjectsTotal,
); err != nil { ); err != nil {
return nil, err return nil, err
} }
@@ -462,11 +468,19 @@ func (a *App) scanProject(row rowScanner, detail bool) (*Project, error) {
p.CreatedAt = timeOut(created) p.CreatedAt = timeOut(created)
p.LastCheckedAt = timeOut(checked) p.LastCheckedAt = timeOut(checked)
p.MinCompetitorPrice = nullableFloat(minPrice) p.MinCompetitorPrice = nullableFloat(minPrice)
if owner, err := a.EmployeeByID(context.Background(), p.OwnerID); err == nil { if ownerID.Valid {
p.Owner = owner p.Owner = &Employee{
ID: ownerID.Int64,
Name: ownerName.String,
PortalUserID: nullableString(ownerPortalID),
TGChatID: nullableString(ownerChatID),
TGUsername: nullableString(ownerUsername),
ProjectsTotal: nullIntValue(ownerProjectsTotal),
CreatedAt: timeOut(ownerCreated),
}
} }
if detail { if detail {
listings, err := a.ListingsForProject(context.Background(), p.ID, true) listings, err := a.ListingsForProject(ctx, p.ID, true)
if err != nil { if err != nil {
return nil, err return nil, err
} }
@@ -480,22 +494,29 @@ func (a *App) ListingsForProject(ctx context.Context, projectID int64, withHisto
if err != nil { if err != nil {
return nil, err return nil, err
} }
defer rows.Close()
items := []Listing{} items := []Listing{}
for rows.Next() { for rows.Next() {
item, err := scanListing(rows, false) item, err := scanListing(rows, false)
if err != nil { if err != nil {
return nil, err return nil, err
} }
if withHistory { items = append(items, *item)
item.PriceHistory, err = a.PriceHistory(ctx, item.ID) }
if err := rows.Err(); err != nil {
rows.Close()
return nil, err
}
rows.Close()
if withHistory {
for i := range items {
history, err := a.PriceHistory(ctx, items[i].ID)
if err != nil { if err != nil {
return nil, err return nil, err
} }
items[i].PriceHistory = history
} }
items = append(items, *item)
} }
return items, rows.Err() return items, nil
} }
func (a *App) PriceHistory(ctx context.Context, listingID int64) ([]PricePoint, error) { func (a *App) PriceHistory(ctx context.Context, listingID int64) ([]PricePoint, error) {