Skip to content

Data Model: Scheduler & Pipeline Assembly

Feature: 007-scheduler-pipeline Date: 2026-05-29

Entities

Run Context (ephemeral, not persisted)

FieldTypeDescription
run_idUUIDUnique identifier for a single pipeline invocation
correlation_idUUIDCorrelation identifier bound to all log entries and OTel spans
start_timefloattime.time() at pipeline start, used for duration recording

Lifecycle: Created at the start of main(), destroyed on process exit. Stored in a ContextVar and structlog context.


ScraperSetting (persisted, owned by 001-article-collection)

FieldTypeDescription
idUUIDPrimary key
sourcestrDisplay name of the scraper source
source_typestrType: rss, blog, arxiv
urlstrFeed URL or listing URL
interval_hoursintMinimum hours between scrapes
is_activeboolWhether the source is eligible for scheduling
last_scraped_atdatetime or NoneTimestamp of the most recent scrape
topic_idUUID or NoneAssociated topic
prompt_overridestr or NoneCustom analysis prompt
selector_configSelectorConfig or NoneScraper-specific configuration
keyword_itemslist[ScraperKeywordVO] or NoneKeyword filter items

Due selection logic (implemented in get_active_due() SQL):

  • is_active = True AND (last_scraped_at IS NULL OR now() - last_scraped_at > interval_hours - 30min tolerance)

State transitions:

[never scraped] ──get_active_due()──> due
[due] ──scrape──> [scraped] (mark_scraped sets last_scraped_at)
[scraped] ──interval+tolerance elapsed──> [due]
[inactive] ──never──> excluded from due selection

CollectionPipeline (ephemeral, assembled per run)

FieldTypeDescription
setting_repoScraperSettingRepositorySource configuration access
executorScrapeExecutorConcurrent discover/fetch engine
event_busInMemoryEventBusSynchronous event dispatch
scraper_factoryConcreteScraperFactoryCreates scrapers per setting

Behaviour: run() -> int — discovers due sources, fetches articles, publishes events, returns count.


FailedTask (persisted, owned by 001-article-collection)

FieldTypeDescription
idUUIDPrimary key
task_typestranalysis, tag_normalization, translation, discover
payloadJSONSerialized task input for retry
error_messagestrException message
created_atdatetimeWhen the failure occurred

Relationships: Created by FailedTaskPersistenceHandler in response to AnalysisFailedEvent, TagNormalizationFailedEvent, TranslationFailedEvent, and the discover-failed callback.


InMemoryEventBus (ephemeral, assembled per run)

Event handler subscriptions (as wired in build_collection_pipeline()):

EventHandlerResult
ArticleScrapedEventArticleScrapedHandlerProcesses article → ArticleProcessedEvent
ArticleProcessedEventArticleProcessedHandlerTriggers analysis → AnalysisCompletedEvent or AnalysisFailedEvent
AnalysisCompletedEventTagNormalizationHandlerNormalizes tags → TagNormalizationCompletedEvent or TagNormalizationFailedEvent
TagNormalizationCompletedEventAnalysisCompletedHandlerTriggers translation for configured languages
AnalysisFailedEventFailedTaskPersistenceHandlerPersists FailedTask
TagNormalizationFailedEventFailedTaskPersistenceHandlerPersists FailedTask
TranslationFailedEventFailedTaskPersistenceHandlerPersists FailedTask
PipelineCompletedEventOtelMetricsHandlerPushes OTel metrics
PipelineCompletedEventNotification handlerSends Telegram notification