MediaWiki Event Enrichment/HTML Feature Counts Enrichment
mw-page-html-feature-counts-change-enrich
Why
Downstream analytics and research often need a compact summary of what changed in the rendered HTML (sections, wikilinks, words, etc.) without storing or re-fetching full HTML. Running mwedittypes on every consumer would duplicate work and increase load.
mw-page-html-feature-counts-change-enrich reads mediawiki.page_html_content_change, reconstructs the parent revision’s HTML from the current HTML and the unified diff, classifies edits with SimpleEditTypes, and emits mediawiki.page_html_feature_counts_change events. The sink payload strips large HTML bodies so the stream stays small.
Enrichment Job
mw-page-html-feature-counts-change-enrich is a PyFlink job in the mediawiki-event-enrichment repository.
Entry point: html_feature_counts_enrichment/page_html_feature_counts_change.py.
What gets processed
- Canary events are dropped before enrichment.
- Only wikitext main-slot events are enriched. Events with non-wikitext content models are dropped.
For remaining events, feature counts are computed only when the change looks like a normal diffable edit:
| Situation | Behaviour |
|---|---|
page_change_kind is create or delete |
Event is passed through without counts. |
rev_parent_id == 0 (no parent revision) |
Event is passed through without counts. |
Edit with HTML body, unified diff, and content_language set |
Enriches event with SimpleEditTypes.
|
Counts are written under delta.revision.rendering.features (software metadata, language, and per–edit-type inserted/removed/modified tallies). Edit-type names from mwedittypes are normalized to the schema’s snake_case keys.
What goes to the error topic
On enrichment failure, the job raises an exception and routes the original event to the error topic. See the Kafka section for topic names. Typical reasons an event might end up in the error topic:
- Missing or empty HTML or diff when enrichment was required (not one of the pass-through cases above).
- Invalid unified diff (cannot reconstruct parent HTML).
- Missing or empty
content_language(required for mwedittypes). SimpleEditTypeserrors (e.g. unsuitable HTML).
Before successful emit, HTML/diff bodies are removed from the payload to keep messages small.
Execution model
Processing is synchronous (process_async_enabled_default: false) to avoid OOM from batching very large HTML messages. The stream is partitioned by (wiki_id, page_id) so ordering per page is preserved while scaling TaskManagers.
Operational
The application is deployed in the mw-page-html-feature-counts-change-enrich namespace of the dse-k8s Kubernetes cluster (eqiad), using the flink-app Helm chart via the Flink Kubernetes Operator. Configuration lives in operations/deployment-charts under helmfile.d/dse-k8s-services/mw-page-html-feature-counts-change-enrich/. A staging release exists under mw-page-html-feature-counts-change-enrich-next/.
For general Kubernetes deployment procedures, see Kubernetes/Deployments.
Upgrades and Deployment
Make changes in the flink application if required in mediawiki-event-enrichment. Once a new docker image has been built and published, we can bump the image version in the relevant helmfile values.yaml file. Once merged, for the most part, the usual kubernetes helmfile deployment process can be followed. But, because this is a streaming Flink application, special care may need to be taken to handle the application restart.
After merging a change to deployment-charts, run the following commands:
## log in to a deployment server
ssh deployment.eqiad.wmnet
## cd into the flink app helm chart
cd /srv/deployment-charts/helmfile.d/dse-k8s-services/mw-page-html-feature-counts-change-enrich
## check changes that will be applied
helmfile -e dse-k8s-eqiad diff
## deploy the application
helmfile -e dse-k8s-eqiad -i apply --context 5
Restart
To force a rolling restart of all pods:
helmfile -e dse-k8s-eqiad --state-values-set roll_restart=1 sync
Destroy
To tear down the deployment completely:
helmfile -e dse-k8s-eqiad -i destroy
Kafka
The application reads from and writes to the Kafka Jumbo cluster. Production consumes both DC-prefixed source topics (eqiad/codfw); only one DC is active at a time, but both topic names are listed so failover does not require a config change.
| Role | Topic pattern (examples) |
|---|---|
| Source | eqiad.mediawiki.page_html_content_change.v1, codfw.mediawiki.page_html_content_change.v1
|
| Sink | eqiad.mediawiki.page_html_feature_counts_change.v1 / codfw.mediawiki.page_html_feature_counts_change.v1
|
| Error / DLQ | eqiad.mw_page_html_feature_counts_change_enrich.error / codfw.mw_page_html_feature_counts_change_enrich.error
|
Sink and error sinks use at-least-once delivery. Maximum request size is aligned with large HTML in error records (20 MB).
Development
Kafka UI
You can set up Kafka UI with Kafbat: javiermonton/kafka-ui-scripts. This helps easily look at existing topics, messages in topics, and some basic stats.
Monitoring
- HTML Edit Types dashboard — throughput, error event counts, and overview metrics shared with the HTML pipeline.
- Flink App dashboard — Flink cluster health, job/task manager status, consumer lag, etc. Select
eqiad prometheus/k8s-dsedatasource,mw-page-html-feature-counts-change-enrichnamespace. - Logs go to Logstash. Select
dse-k8scluster andmw-page-html-feature-counts-change-enrichnamespace. - More here (e.g. Flink UI): MediaWiki_Event_Enrichment#Monitoring
Backfilling
On restarts, the job catches up from the last Kafka offset. If the job restarts soon after, the catchup should not be a problem. If it has been down for a while (days), the catchup can take a long time and may fire HighKafkaConsumerLag alert. Increase TaskManager replicas temporarily to speed up for big backfills.
helmfile apply -e dse-k8s-eqiad --set app.taskManager.replicas=20
Alerting
Alerts are defined in operations/alerts under team-data-engineering/mw-page-html-feature-counts-change-enrich.yaml and fire only on the dse-k8s cluster.
- Severity
- Critical
- Condition
- No
flink_jobmanager_job_uptimemetric is present for the job for more than 5 minutes. - Meaning
- The Flink JobManager is not running. The enrichment pipeline is completely down.
- Actions
- Check the HTML Edit Types dashboard.
- Check Kubernetes pod status in the
mw-page-html-feature-counts-change-enrichnamespace. - Check logs to see if the application is failing for a reason.
- Redeploy if needed.
- Severity
- Critical
- Condition
- The Flink cluster has zero registered TaskManagers for more than 5 minutes.
- Meaning
- The Flink application is running but there are no workers. No events are being processed.
- Actions
- Check TaskManager pod logs and the HTML Edit Types dashboard.
- Check logs to see if the application is failing for any reason. Redeploy if needed.
- Check if there's an issue with Kubernetes, like not enough resources.
- Severity
- Warning
- Condition
- More than 0.05% of messages are routed to the error topic over a 10-minute window.
- Meaning
- A significant fraction of events cannot be enriched. This may indicate a major bug during the enrichment, malformed events, or oversized payloads.
- Actions
- Check the HTML Edit Types dashboard
- There is a widget with the number of messages sent to the error topic, as well as the %
- Inspect the error and output topics in Kafka
- Review Flink and Envoy logs.
- Severity
- Critical
- Condition
- No messages are produced to the output topic in the last 30 minutes.
- Meaning
- The job has stalled or is exclusively routing events to the error topic.
- Actions
- Check the HTML Edit Types dashboard
- Check whether Flink and Envoy are running
- Check Flink UI and whether there is traffic on the source or error topic.
- If everything looks good, maybe the source is failing or routing messages to another Kafka topic, like another version of the topic.
- Severity
- Warning
- Condition
- The maximum Kafka consumer lag across partitions exceeds 1200 records for more than 5 minutes.
- Meaning
- The job is falling behind its input rate. This can be triggered if the application is down or if it is working slower than expected. Can fire during backfills.
- Actions
- Check the HTML Edit Types dashboard for resource bottlenecks (CPU, memory, network)
- Check if there was an outage, maybe the job is already recovering but it will need time.
- Consider increasing replicas (TaskManagers) to recover faster.