Not a member of Pastebin yet?
Sign Up,
it unlocks many cool features!
- """
- The solution you are writing is part of a marketing engine for our StubHub website.
- You will be implementing the setup and business logic for different marketing campaigns that find “relevant” events for a user and notifies them accordingly.
- We are first looking for the correctness and performance of your solution, but also the extensibility and long-term maintainability.
- Q1
- This code is missing some key elements. Define the MarketingEngine class and implement a send_customer_notifications method to notify the customer of all the events happening in the same city as the customer.
- While in the real world we would notify the customer of these events via email or text, for the purposes of this exercise, we want you to output the text content we intend to send to the customer and print it to the console.
- Please note that this method will be invoked multiple times for multiple different customers.
- Notes:
- - Make sure to ask if the timezone matters, e.g. do we need to send a batch of notifications
- at 12 PM Eastern Time and another batch at 12 PM Pacific Time?
- - Ask clarifying questions, like what if there is a tie where two events happen at the same time.
- What should you do in that scenario? Just take the first event.
- Q2
- Extend the solution to add a new campaign which sends a notification to the customer with the event closest to their next or upcoming birthday.
- Please note that this campaign will be run multiple times for multiple different customers.
- # Just pick the first event
- # 100_000 customers
- Q3
- We now need to implement a new campaign that notifies the customer of the 5 closest events to the customer based on the distance between the customer and the event.
- You should assume that we have about 10 million events and we need to call this per user.
- Q4
- In the stubhub backend we have a simple restful api that you can call that will return prices for events:
- For all event prices: https://sh-mockapi.azurewebsites.net/api/ticketprice
- For a price per event: https://sh-mockapi.azurewebsites.net/api/ticketprice?eventId={EventId}
- i.e https://sh-mockapi.azurewebsites.net/api/ticketprice?eventId=1
- Can you call this service from your solution to send a notification of the 5 cheapest tickets within a Y mile radius of the customer? We can test with various radiuses.
- """
- from bisect import bisect_left
- from collections import defaultdict
- from dataclasses import dataclass
- from datetime import datetime, timedelta
- from dateutil import parser
- from math import sqrt
- import requests
- from typing import List
- from requests.models import Response
- class City:
- name: str
- x_cor: int
- y_cor: int
- '''
- /*-------------------------------------
- Coordinates are roughly to scale with miles in the USA
- 2000 +----------------------+
- | |
- | |
- Y | |
- | |
- | |
- | |
- | |
- 0 +----------------------+
- 0 X 4000
- ---------------------------------------*/
- '''
- # Assume a static number of cities
- CITY_MAP : dict[str, City]= {
- 'New York': City('New York', 3572, 1455),
- 'Los Angeles': City('Los Angeles', 462, 975),
- 'Boston': City('Boston', 3778, 1566),
- 'Chicago': City('Chicago', 2608, 1525),
- 'San Francisco': City('San Francisco', 183, 1233),
- 'Washington': City('Washington', 3358, 1320)
- }
- def distance(city1: City, city2: City) -> float:
- return sqrt(
- (city1.x_cor - city2.x_cor) * (city1.x_cor - city2.x_cor) +
- (city1.y_cor - city2.y_cor) * (city1.y_cor - city2.y_cor)
- )
- class Event:
- id: int
- name: str
- city: str
- event_date: datetime
- class Customer:
- id: int
- name: str
- city: str
- birth_date: datetime
- class MarketingEngine:
- def __init__(self, events: List[Event]):
- now: datetime = datetime.now()
- self.events: List[Event] = [
- event for event in events if event.event_date >= now
- ]
- self.city_to_events: dict[str, List[Event]] = defaultdict(list)
- for event in self.events:
- self.city_to_events[event.city].append(event)
- event_date_to_event: dict[datetime, Event] = {event.event_date: event for event in self.events}
- self.events_sorted_by_date = sorted(
- event_date_to_event.values(), key=lambda event: event.event_date
- )
- self.closest_threshold: int = 5
- self.prices_ttl: timedelta = timedelta(days=1)
- self.last_price_cache: datetime = datetime.now()
- price_data = requests.get("https://sh-mockapi.azurewebsites.net/api/ticketprice").json()
- self.id_to_event = {int(event["Id"]): event for event in price_data}
- def send_customer_notifications(self, customer: Customer) -> None:
- # "Sends" notifications via the print method
- print(f"Calling send_customer_notifications for customer {customer.name}")
- result = self.city_to_events.get(customer.city, [])
- print(result)
- def send_customer_notifications_by_birthday(self, customer: Customer) -> None:
- # log(|EVENTS|)
- if not self.events_sorted_by_date:
- print(f"No events for {customer}")
- base_birthdate = customer.birth_date
- now: datetime = datetime.now()
- next_birthday = datetime(now.year, base_birthdate.month, base_birthdate.day)
- if now > next_birthday:
- next_birthday = datetime(now.year + 1, next_birthday.month, next_birthday.day)
- print(f"{next_birthday=}")
- idx = bisect_left(self.events_sorted_by_date, next_birthday, key=lambda event: event.event_date)
- # If you're sandwiched between two events, which is closer?
- if idx > 0:
- time_diff_right = abs(self.events_sorted_by_date[idx].event_date - next_birthday)
- time_diff_left = abs(self.events_sorted_by_date[idx - 1].event_date - next_birthday)
- if time_diff_left <= time_diff_right:
- print(self.events_sorted_by_date[idx - 1])
- return
- print(self.events_sorted_by_date[idx])
- def send_customer_notifications_by_proximity(self, customer: Customer) -> None:
- customer_city = CITY_MAP.get(customer.city)
- if not customer_city:
- print(f"No city found for {customer}")
- result = []
- nearest_cities = sorted(CITY_MAP.values(), key=lambda city: distance(customer_city, city))
- for city in nearest_cities:
- events = self.city_to_events[city.name]
- for event in events:
- result.append(event)
- if len(result) == self.closest_threshold:
- break
- if len(result) == self.closest_threshold:
- break
- print("Closest events: ")
- print(result)
- def part_4(self, customer: Customer, radius: int) -> None:
- customer_city = CITY_MAP.get(customer.city)
- if not customer_city:
- print(f"No city found for {customer}")
- return
- now = datetime.now()
- if now - self.last_price_cache < self.prices_ttl:
- price_data = requests.get("https://sh-mockapi.azurewebsites.net/api/ticketprice").json()
- # print(price_data)
- self.id_to_event = {int(event["Id"]): event for event in price_data}
- self.last_price_cache = now
- # 5 cheapest tickets in a y-mile radius
- cities_within_radius = [
- city for city in CITY_MAP.values() if distance(city, customer_city) <= radius
- ]
- event_ids_in_the_radius: List[int] = []
- for city in cities_within_radius:
- event_ids_in_the_radius.extend(event.id for event in self.city_to_events.get(city.name, []))
- print(f"{event_ids_in_the_radius=}")
- # List[(price, event)]
- prices_and_events = []
- for event_id in event_ids_in_the_radius:
- price = self.id_to_event[event_id]["Price"]
- prices_and_events.append((float(price), self.id_to_event[event_id]))
- prices_and_events.sort()
- if len(prices_and_events) < 5:
- prices_and_events = prices_and_events[:5]
- print([event for _, event in prices_and_events])
- def main():
- events: list[Event] = [
- Event(1, "Phantom of the Opera", "New York", parser.parse("2023-12-23")), # X
- Event(2, "Metallica", "Los Angeles", parser.parse("2024-12-02")), # OK
- Event(3, "Metallica", "New York", parser.parse("2024-12-06")), # OK
- Event(4, "Metallica", "Boston", parser.parse("2024-10-23")), # OK
- Event(5, "LadyGaGa", "New York", parser.parse("2023-09-20")),
- Event(6, "LadyGaGa", "Boston", parser.parse("2024-08-01")), # OK
- Event(7, "LadyGaGa", "Chicago", parser.parse("2024-07-04")), # OK
- Event(8, "LadyGaGa", "San Francisco", parser.parse("2024-07-07")), #OK
- Event(9, "LadyGaGa", "Washington", parser.parse("2023-05-22")),
- Event(10, "Metallica", "Chicago", parser.parse("2024-01-01")),
- Event(11, "Phantom of the Opera", "San Francisco", parser.parse("2024-07-04")),
- Event(12, "Phantom of the Opera", "Chicago", parser.parse("2025-05-15")),
- ]
- customer: Customer = Customer(1, "Avos", "New York", parser.parse("1995-05-11"))
- engine: MarketingEngine = MarketingEngine(events)
- # engine.send_customer_notifications(customer)
- # engine.send_customer_notifications_by_birthday(customer)
- # print()
- # print("By proximity: ")
- # engine.send_customer_notifications_by_proximity(customer)
- engine.part_4(customer, 2000)
- ```
- ==============
- Design a system that will send 1,000,000 recommendation emails to users in 5 minutes.
- These emails must be sent from 12:00 PM to 12:05 PM.
- Answer:
- - You cannot create the recommendations within 5 minutes. You must create the recommendations in the
- hour or two beforehand.
- - Ask your interviewer whether the email service is a black box, or whether you own the service.
- When it comes to email, some users will ultimately complain that they aren't getting their
- emails even if you send them, so you might need SMTP logs to prove that you're sending the emails.
- This is usually easier to do if you own the email service.
- - Discuss other problems that accompany email systems, like failure, retries, at-least-once delivery, and dead lettering.
- - I gave calculations for the number of worker nodes that we need for the email service. I don't know
- whether this is necessary.
- - You will be asked about business statistics etc. that you should collect. Open rate, click through rate,
- conversion rate, A/B testing success metrics etc. are the ones you should talk about.
- - You will be asked about system metrics to collect. You should collect metrics on email failure, retries, complaints.
- You should also figure out how long it takes for the recommendation system to prepare 1,000,000 recommendations.
- - You should talk about what to do if each component fails. If the recommendation system fails, you should have default recommendations.
- Feel free to ask questions. See my diagram.
- My diagram:
- https://imgur.com/RyaMzg5
- ============
- Director of Engineering Interview
- Talk about a project you're particularly proud of. The project can be one you’re particularly proud of, or one you’ve learned a lot from. Be sure to share the
- accomplishments from this project; again, noting both technical accomplishments, and data points at how this project impacted the business as whole, are great ways to get your impact across to the team.
- Talk about getting blocked by another team.
- Talk about a disgreement in priorities with another team.
- Talk about a technical challenge that you faced.
- Then do your creative pitch. Don't overthink it.
- Hiring Manager Interview:
- Introductions. He talks about what his teams do. What his roadmap is. He gave me a ton of time to ask questions. The only question he had for me was a time where I had a disagreement with someone else. I asked whether he wanted a technical or interpersonal disagreement. He said either. I went with a technical disagreement.
Advertisement
Add Comment
Please, Sign In to add comment