← Atlassian Interview Insights

Atlassian·Software Engineer·Onsite - System Design / Architecture·Senior

SeniorPrefer not to say
Apr 2026

Summary

Atlassian system design round for a software engineer role, focused entirely on building an image crawler from scratch. The scope kept expanding as the conversation went on, which I wasn't fully ready for.

Questions Asked (4)

Q1

Design an image crawler that starts from one or more root URLs, crawls pages to arbitrary depth, and downloads and stores the images it finds.

System DesignData ModelingTechnical Trade-offs
Author's notes

I started with the obvious stuff, a queue of URLs, workers pulling from it, storing images somewhere.

Create a free account to read the full note

AI HintsAI Generated

Suggested Approach

Start by clarifying requirements such as scale, depth limits, politeness, and storage needs. Then propose a high-level architecture with a crawler, parser, downloader, and storage components, and dive into key design decisions like URL frontier management, deduplication, and trade-offs between depth and resource usage.

Pro tip: Emphasize politeness and legal considerations (robots.txt, rate limiting) early, as this shows production awareness beyond just technical design. Also, discuss how you would handle dynamic content and JavaScript-rendered images, which is often overlooked.

1. Clarify Requirements and Scope

Ask about scale (number of URLs, depth, image volume), politeness constraints, storage requirements, and whether dynamic content needs handling. This ensures the design meets actual needs.

2. High-Level Architecture

Outline main components: URL frontier (queue), fetcher (HTTP client), parser (HTML parser), image downloader, and storage (file system or object store). Mention distributed crawling if scale demands.

3. Core Design Decisions

Discuss URL deduplication (Bloom filter or hash set), depth control (BFS with depth tracking), politeness (rate limiting per domain, robots.txt), and handling failures/retries.

4. Data Modeling and Storage

Design how to store images (e.g., S3 with metadata in DB) and crawled URLs (e.g., NoSQL for visited URLs). Consider deduplication of images via hashing.

5. Trade-offs and Scalability

Discuss trade-offs: depth vs. resource usage, breadth-first vs. depth-first, synchronous vs. asynchronous downloading, and scaling horizontally with distributed queues.

Key Points to Mention

  • Politeness: respect robots.txt, rate limiting per domain, and user-agent identification.
  • Deduplication: avoid re-crawling URLs and re-downloading images using hashing (e.g., SHA-256) and Bloom filters.
  • Depth control: use BFS with a depth parameter to limit crawl depth and prevent infinite loops.
  • Storage: separate image storage (object store) from metadata (database) for scalability and cost efficiency.
  • Scalability: distribute crawling across multiple workers with a centralized queue (e.g., Kafka, Redis) and handle failures with retries and dead-letter queues.
  • Dynamic content: consider using headless browsers (e.g., Puppeteer) for JavaScript-rendered images, but note the performance trade-off.

AI-generated suggestions, not part of the candidate's original notes. May be inaccurate — verify before relying on them.

Q2

How would you model the database schema to track URLs, their fetch state, crawl depth, parent links, and image metadata?

Data ModelingSystem Design
Author's notes

This is where I actually felt okay.

Create a free account to read the full note

AI HintsAI Generated

Suggested Approach

Start by clarifying the requirements and scale, then propose a normalized schema with separate tables for URLs, fetch state, and image metadata, using foreign keys to represent parent-child relationships. Explain how you would handle crawl depth and ensure efficient querying for state transitions and hierarchy traversal.

Pro tip: Mention that you would use an enum for fetch state and consider adding a 'next_fetch_at' timestamp for scheduling retries, showing you think about operational concerns beyond just data storage.

1. Clarify requirements and scale

Ask about expected volume, read/write patterns, and whether the system needs to support concurrent crawlers. This ensures your design meets actual needs.

2. Design core URL table

Create a 'urls' table with columns for id, url (unique), fetch_state (enum), crawl_depth, parent_id (self-referencing FK), and timestamps. This centralizes URL metadata.

3. Add image metadata table

Create an 'images' table with a foreign key to the URL it was found on, storing metadata like src, alt, dimensions, and format. This keeps image data separate and scalable.

4. Optimize for queries and updates

Add indexes on fetch_state, parent_id, and crawl_depth to support efficient state transitions and hierarchy traversal. Consider partitioning if volume is high.

5. Discuss trade-offs and extensions

Mention alternatives like using a graph database for complex relationships or adding a separate table for fetch history. Explain why a relational model is suitable here.

Key Points to Mention

  • Use of self-referencing foreign key for parent links to represent the crawl tree.
  • Enum or lookup table for fetch state (e.g., pending, fetching, fetched, failed) to ensure consistency.
  • Storing crawl depth as an integer to easily limit or analyze crawl depth.
  • Separate table for image metadata with a foreign key to the URL, avoiding wide tables and enabling one-to-many relationships.
  • Indexing strategy on fetch_state and parent_id for efficient querying and updates.
  • Consideration of unique constraint on URL to prevent duplicates and ensure idempotency.

AI-generated suggestions, not part of the candidate's original notes. May be inaccurate — verify before relying on them.

Q3

How would you handle failures in the crawl pipeline, including retries, a dead-letter queue, and resuming after a partial failure?

System DesignTechnical Trade-offs
Author's notes

Exponential backoff came out of my mouth pretty fast.

Create a free account to read the full note

AI HintsAI Generated

Suggested Approach

Start by clarifying the crawl pipeline's requirements and failure modes, then propose a layered resilience strategy: retries with backoff, a dead-letter queue for poison messages, and checkpointing for resumability. Emphasize idempotency and observability to ensure safe recovery and debugging.

Pro tip: Atlassian values pragmatic trade-offs: explicitly discuss when to retry versus fail fast, and how you'd monitor DLQ depth and alert on it. Also mention that you'd design for idempotency from the start to avoid duplicate work during retries or resumption.

1. Clarify requirements and failure modes

Ask about the pipeline's scale, latency tolerance, and types of failures (transient vs. permanent). Identify what 'partial failure' means in this context and the expected recovery time.

2. Design retry mechanism

Propose retries with exponential backoff and jitter for transient errors, with a maximum retry limit. Ensure operations are idempotent to avoid duplicate side effects.

3. Introduce dead-letter queue (DLQ)

After max retries, route failed messages to a DLQ for later analysis and manual reprocessing. Include metadata like error reason and timestamp for debugging.

4. Implement checkpointing and resumption

Use durable checkpoints (e.g., after each batch or page) to track progress. On restart, resume from the last checkpoint, skipping already-processed items.

5. Add monitoring and alerting

Track retry counts, DLQ size, and checkpoint lag. Alert on anomalies and provide dashboards for visibility into pipeline health.

Key Points to Mention

  • Idempotency: ensure operations can be safely retried without side effects.
  • Exponential backoff with jitter to avoid thundering herd.
  • Dead-letter queue for poison messages and manual intervention.
  • Checkpointing for resuming after partial failures.
  • Monitoring and alerting on retries, DLQ depth, and checkpoint lag.
  • Trade-offs: retry limits vs. latency, DLQ storage cost vs. data loss.

AI-generated suggestions, not part of the candidate's original notes. May be inaccurate — verify before relying on them.

Q4

How would you implement rate limiting per domain and respect robots.txt rules across a distributed set of crawler workers?

System DesignTechnical Trade-offs
Author's notes

Robots.txt I handled by caching the parsed rules per domain with a TTL.

Create a free account to read the full note

AI HintsAI Generated

Suggested Approach

Start by clarifying requirements and constraints, then propose a distributed architecture with a central coordination service (e.g., Redis) for per-domain rate limits and a shared robots.txt cache. Discuss trade-offs between consistency, latency, and fault tolerance, and explain how workers enforce limits and respect robots.txt before fetching.

Pro tip: Emphasize that rate limiting should be per-domain, not per-worker, and that robots.txt caching must handle updates and failures gracefully. Mention using a token bucket algorithm with Redis and a TTL-based cache for robots.txt to balance freshness and performance.

1. Clarify requirements and constraints

Ask about scale (number of domains, workers, request rate), latency tolerance, consistency needs, and whether robots.txt changes must be detected quickly. This shows you think before designing.

2. Design distributed rate limiting

Propose a central store (e.g., Redis) with atomic operations to implement per-domain token buckets or sliding windows. Workers check and decrement tokens before fetching, ensuring global limits across all workers.

3. Implement robots.txt handling

Use a shared cache (e.g., Redis or a dedicated service) to store parsed robots.txt rules per domain with a TTL. Workers fetch and parse robots.txt on cache miss, and respect rules before crawling.

4. Address failure and consistency

Discuss fallbacks if the central store is unavailable (e.g., local rate limiting with conservative limits) and how to handle stale robots.txt (e.g., serve stale on error, revalidate in background).

5. Discuss trade-offs and optimizations

Compare centralized vs. decentralized approaches, mention sharding by domain for scalability, and consider using a dedicated service for rate limiting and robots.txt to reduce worker complexity.

Key Points to Mention

  • Token bucket or sliding window algorithm for rate limiting
  • Redis or similar in-memory store for atomic operations and low latency
  • Per-domain rate limiting to avoid overwhelming individual sites
  • Robots.txt caching with TTL and graceful degradation on fetch failures
  • Handling of robots.txt updates and cache invalidation
  • Trade-offs between consistency, availability, and latency in distributed systems

AI-generated suggestions, not part of the candidate's original notes. May be inaccurate — verify before relying on them.