Skip to content
This repository was archived by the owner on Apr 23, 2026. It is now read-only.

Latest commit

 

History

History
307 lines (216 loc) · 5.96 KB

File metadata and controls

307 lines (216 loc) · 5.96 KB

✨Dvurechensky✨

AdPlatformService - Junior .NET Test Task 📄

🌐 Language: 🇷🇺 Russian | ✅ 🇺🇸 English (current)

AdPlatformService is a high-performance in-memory web service for storing and searching advertising platforms by location.

📄 Task documentation is also available in PDF: TASK.NET.pdf
📄 Test input file: test_input_data.txt

⭐ Table of Contents


🚀 Run

Start

dotnet run --project AdRegionService

Debug

👉 API: http://localhost:5411 👉 Swagger UI: http://localhost:5411/swagger

Release

👉 API: http://localhost:5411 👉 Swagger UI: http://localhost:5411/swagger


API

Show API details
POST /api/load
Content-Type: multipart/form-data

file=@platforms.txt
{
	"message": "Data loaded",
	"loaded": 123,
	"skipped": 5
}
GET /api/search?location=/ru/svrd
[
	{ "name": "Cool Ads", "locations": ["/ru/svrd"] },
	{
		"name": "Revdinsky Worker",
		"locations": ["/ru/svrd/revda", "/ru/svrd/pervik"]
	}
]

✨ Features

  • 📂 Load advertising platforms from file (Stream)

  • ⚡ In-memory storage using immutable collections

  • 📊 Load statistics (loaded / skipped)

  • 🔍 Hierarchical location search:

    • /loc1 matches all platforms under this level
    • /loc1/loc2 also includes /loc1
  • 🛡 Error handling:

    • OperationCanceledException
    • OutOfMemoryException
    • General errors are logged, state remains consistent

🔹 Core Functionality

1. Loading platforms from file

Method:

LoadFromStreamAsync(Stream stream, CancellationToken cancellationToken = default)

Key Features

  • ✅ Accepts Stream (supports files and network sources)

  • ✅ Ignores invalid lines:

    • empty lines
    • missing :
    • empty platform name
    • no valid locations
  • ✅ Location indexing Stored in:

ImmutableDictionary<string, ImmutableHashSet<AdPlatform>>
  • ✅ Load statistics (LoadStats)
  • ✅ Progress logging every 100,000 lines
  • ✅ Error resilience:
    • keeps previous state on failure
    • logs all exceptions

Example file format

Yandex.Direct:/ru
Revdinsky Worker:/ru/svrd/revda,/ru/svrd/pervik
Ural Moscow Newspaper:/ru/msk,/ru/permobl,/ru/chelobl
Cool Ads:/ru/svrd

2. Search by location

  • ✅ Method: Search(string location)
  • ✅ Uses indexed lookup (no full scan)
  • ✅ Supports hierarchical matching
  • ✅ Returns IEnumerable<AdPlatform>
  • ✅ Thread-safe
  • ⚡ Efficient up to:
    • 1–2 million entries
    • 100–500 MB data

For >10M entries → consider external storage (PostgreSQL, full-text search, etc.)


🔹 Technical Approach

Immutable Collections

  • ImmutableArray
  • ImmutableDictionary
  • ImmutableHashSet

➡️ Thread-safe without locks


Hierarchical Index

Search /a/b/c → checks:

  • /a
  • /a/b
  • /a/b/c

Logging

  • ILogger
  • Progress logging
  • Error tracking
  • Ready for integration (Seq, Kibana, etc.)

Fault Tolerance

  • Invalid data is skipped
  • State is preserved on failure
  • Search never throws exceptions

Set-based Search

  • Uses HashSet<AdPlatform>
  • Removes duplicates automatically
  • Returns lightweight enumerable

🔹 Advantages

  • ⚡ High performance (1–2M entries)
  • 🛡 Robust error handling
  • 🔗 Easy REST integration
  • 🧵 Thread-safe architecture

🔹 Testing

  • xUnit tests

  • Covers:

    • loading
    • search
    • edge cases
  • Run:

dotnet test

🛠 CI/CD

  • Docker build on push to main
  • Publish to GitHub Container Registry
  • dotnet build + dotnet test

🔹 Docker

Generate certificate

openssl req -x509 -nodes -days 365 -newkey rsa:2048 -keyout key.pem -out cert.pem -subj "/CN=localhost"

Run container

docker-compose up --build

Access


Pull image

docker pull ghcr.io/dvurechensky/net_junior_ads_test_task/adservice:latest

Run

docker run -it --rm -p 5411:5411 ghcr.io/dvurechensky/net_junior_ads_test_task/adservice:latest

✨Dvurechensky✨