Войти Регистрация
Код-ревью

31. Лента друзей ВКонтакте

Сложная

Go · 53 строк

Обработчик отдаёт ленту постов друзей, новые сверху. Клиент листает её курсором: before — время последнего показанного поста, limit — размер страницы, приложение шлёт 30.

У активного пользователя 300–1 000 друзей, у друга в среднем 2 000 постов за всё время. Пул соединений — SetMaxOpenConns(50), обработчик держит 3 000 запросов в секунду на под. Отметьте строки с ошибками.

В работе: Вкладка «Друзья» в ленте: первый экран после открытия приложения.

Как проверяем Нажмите на строку с ошибкой и коротко напишите, что не так. Баг засчитан, если отмечена хотя бы одна его строка. Зачёт — найдено не меньше 60 % багов с учётом серьёзности (критичный весит 3, обычный 2, мелкий 1), а лишних отметок не больше, чем багов в коде. Пустые строки, скобки и комментарии лишними не считаем. Ответ один на подход: после него показываем разбор.
Godatabase/sqlпагинацияN+1пул соединенийдоступ

Источник: наша задача на данных VK: лента и друзья. Условие пересказано своими словами.

  1. package feed
  2. import (
  3. "database/sql"
  4. "encoding/json"
  5. "net/http"
  6. "sort"
  7. "strconv"
  8. )
  9. type Post struct {
  10. ID int64 `json:"id"`
  11. AuthorID int64 `json:"author_id"`
  12. Author string `json:"author"`
  13. Text string `json:"text"`
  14. CreatedAt int64 `json:"created_at"`
  15. Likes int `json:"likes"`
  16. }
  17. type Service struct {
  18. db *sql.DB
  19. }
  20. func (s *Service) Feed(w http.ResponseWriter, r *http.Request) {
  21. userID, _ := strconv.ParseInt(r.URL.Query().Get("user_id"), 10, 64)
  22. limit, _ := strconv.Atoi(r.URL.Query().Get("limit"))
  23. before, _ := strconv.ParseInt(r.URL.Query().Get("before"), 10, 64)
  24. rows, err := s.db.QueryContext(r.Context(),
  25. "SELECT p.id, p.author_id, p.text, p.created_at, p.likes FROM posts p "+
  26. "JOIN friends f ON f.friend_id = p.author_id "+
  27. "WHERE f.user_id = $1 AND p.created_at < $2",
  28. userID, before)
  29. if err != nil {
  30. http.Error(w, err.Error(), http.StatusInternalServerError)
  31. return
  32. }
  33. defer rows.Close()
  34. var posts []Post
  35. for rows.Next() {
  36. var p Post
  37. rows.Scan(&p.ID, &p.AuthorID, &p.Text, &p.CreatedAt, &p.Likes)
  38. s.db.QueryRowContext(r.Context(), "SELECT name FROM users WHERE id = $1", p.AuthorID).Scan(&p.Author)
  39. posts = append(posts, p)
  40. }
  41. sort.Slice(posts, func(i, j int) bool { return posts[i].CreatedAt > posts[j].CreatedAt })
  42. if len(posts) > limit {
  43. posts = posts[:limit]
  44. }
  45. json.NewEncoder(w).Encode(posts)
  46. }