Skip to content

Send messages to docs.rs after crate actions#14188

Draft
LawnGnome wants to merge 8 commits into
rust-lang:mainfrom
LawnGnome:docs-rs-sqs
Draft

Send messages to docs.rs after crate actions#14188
LawnGnome wants to merge 8 commits into
rust-lang:mainfrom
LawnGnome:docs-rs-sqs

Conversation

@LawnGnome

@LawnGnome LawnGnome commented Jul 9, 2026

Copy link
Copy Markdown
Contributor

This is a sketch of how we might close #14111 by sending messages to docs.rs. It is best reviewed commit-by-commit.1

I do not expect to merge this in its current form; this draft PR is primarily to gather feedback.

How it works

Very broadly, we need to do the following:

  • Refactor the existing configuration logic used for CdnLogQueueConfig to be generic so we can reuse it for the docs.rs queue.
  • Add a docs.rs queue.
  • Add message sending functionality to SqsQueue.
  • Change the SyncToGitIndex job to include the event that triggered the sync2, which can then be turned into a message.
  • Actually send the message.

Open questions

I'm not particularly set on this particular implementation. Things I'd like feedback on include:

  1. Should this live in the SyncToGitIndex job at all?
    1. If not, should this be a job triggered by SyncToGitIndex, or should this be decoupled from the Git index sync altogether?3
  2. How do we alert on this when sending a message fails, and what happens then?
  3. Are the new SqsQueueImpl tests actually useful?
  4. Similarly, is the smoke test now too big and clunky to be useful in its current form?4

Other prerequisites and testing

This depends on rust-lang/simpleinfra#1099. Once that's merged, we could deploy this (or whatever comes out of this) to staging and start testing with a stub consumer to ensure that we get the messages we expect to see.

I'm unsure if the docs.rs team wants to actually publish the docs_rs_crates_io crate, but if they do, then that would also need to happen.

Footnotes

  1. I expect that, in practice, we might want to split the SQS commits into a separate PR since they're technically a separate refactor.

  2. There are still cases where we won't have a trigger that's relevant to docs.rs, most notably manual syncs to the index initiated via crates-admin.

  3. The main motivator behind tying this to the Git index sync is that docs.rs uses the Git index to pull crate metadata, so having the message only be sent after the Git index has already been updated means that docs.rs doesn't need to care about whether the update has occurred.

  4. In particular, I don't love how big that function has now gotten with the usage of MockSqsQueue.

LawnGnome added 8 commits July 9, 2026 15:41
Rather than special casing the CDN log queue configuration, we make the
configuration shared so we can reuse it for the docs.rs queue configuration.

One of `config::queue` and `sqs` ends up needing to know about the
other. Since `config` modules are generally simple, this has been
implemented in `sqs`, which means that it is no longer self-contained,
but does mean that we follow the same general pattern as other service
clients.
As with the other trait methods, this is a thin wrapper around
`aws_sdk_sqs`.
I have some mixed feelings on the utility of these tests, since they're
really just validating that the very thin `SqsQueueImpl` methods are
passing the right things between the caller and `aws_sdk_sqs`, but
:shrug:.
This will be used to build the appropriate SQS message to docs.rs when
set.
Comment thread src/sqs.rs
(**self).receive_messages(max_messages).await
}

async fn send_message(&self, message: String) -> anyhow::Result<SendMessageOutput> {

@carols10cents carols10cents Jul 13, 2026

Copy link
Copy Markdown
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Nit: As of this commit, the SqsQueue trait doesn't have the send_message method on it. That is, if you check out this commit, I don't think it will build.

View changes since the review

Copy link
Copy Markdown
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

yeah, I think this was meant to be introduced two commits later in the "Add SqsQueue::send_message" commit

Comment thread Cargo.toml
diesel-async = { version = "=0.9.2", features = ["async-connection-wrapper", "deadpool", "postgres"] }
diesel_full_text_search = "=2.3.0"
diesel_migrations = { version = "=2.3.2", features = ["postgres"] }
docs_rs_crates_io = { git = "https://github.com/rust-lang/docs.rs.git", rev = "1604301c72411fbc63082434295fa45036d982b7", version = "0.1.0" }

@carols10cents carols10cents Jul 13, 2026

Copy link
Copy Markdown
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

just pointing out for other reviewers that the docs_rs_crates_io crate and this rev are from rust-lang/docs.rs#3357

View changes since the review

Copy link
Copy Markdown
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

and I assume we won't rely on a git dependency once we merge this, right? 😅

@carols10cents

Copy link
Copy Markdown
Member

🤷🏻‍♀️ seems fine to me

Comment thread src/sqs.rs
(**self).receive_messages(max_messages).await
}

async fn send_message(&self, message: String) -> anyhow::Result<SendMessageOutput> {

Copy link
Copy Markdown
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

yeah, I think this was meant to be introduced two commits later in the "Add SqsQueue::send_message" commit

Comment thread Cargo.toml
diesel-async = { version = "=0.9.2", features = ["async-connection-wrapper", "deadpool", "postgres"] }
diesel_full_text_search = "=2.3.0"
diesel_migrations = { version = "=2.3.2", features = ["postgres"] }
docs_rs_crates_io = { git = "https://github.com/rust-lang/docs.rs.git", rev = "1604301c72411fbc63082434295fa45036d982b7", version = "0.1.0" }

Copy link
Copy Markdown
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

and I assume we won't rely on a git dependency once we merge this, right? 😅

Comment on lines +23 to +28
/// The triggering event that led to the sync.
///
/// Once the index has been synced, this event will be sent to docs.rs via
/// SQS.
#[serde(default)]
trigger: Option<Trigger>,

@Turbo87 Turbo87 Jul 14, 2026

Copy link
Copy Markdown
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

unfortunately I think this defeats the purposed of the const DEDUPLICATED: bool = true; below. we explicitly introduced the deduplication to avoid having to sync every update in isolation to the indexes because it was causing performance problems. if we include the triggers then either we don't deduplicate anymore, or we keep deduplicating but docs.rs might miss deduplicated events, or both.

it might also block us from potentially batching index updates in the future for related reasons.

does docs.rs really need this information? we can easily give them the added/updated/deleted information, but the yanked/unyanked/version-deleted would be slightly more complicated since we might combine multiple of these in a single commit.

View changes since the review


let crate_name = self.krate.clone();
let mut conn = env.deadpool.get().await?;
let queue = env.docs_rs_queue.clone();

@Turbo87 Turbo87 Jul 14, 2026

Copy link
Copy Markdown
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

we should probably make this queue optional, so that it does not break the publishing flow when developing locally without having a queue configured. the default-to-mock behavior for the other queue was okayish in the past because the corresponding background job that used the queue had to be triggered manually anyway, but this one is triggered by the regular publish flow and yank/unyank. this might involve changing QueueConfig::from_env() to return Result<Option<Self>> or something like that.

View changes since the review

Comment on lines +171 to +178
// TODO: is this alertable? How can we notify docs.rs that rebuilds
// may be required?
error!(
krate.name = &self.krate,
trigger = ?self.trigger,
error = %e,
"error notifying docs.rs",
);

@Turbo87 Turbo87 Jul 14, 2026

Copy link
Copy Markdown
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

you could do something like warn!(target: "docs_rs_queue", ...) which makes it easy to filter on in Datadog

I'd also recommend to not use structured logging too much unless you plan on filtering by these fields, and including the fields in the log message too, so that not every log row on Datadog reads "error notifying docs.rs" without any context. something like "Failed to notify docs.rs about {trigger} update on {krate} crate: {error}" is much easier to comprehend at a glance without having to dig into the details of every log event (see https://github.com/rust-lang/crates.io/blob/main/docs/LOGGING.md) :)

View changes since the review

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Projects

Status: For next meeting

Development

Successfully merging this pull request may close these issues.

Notify docs.rs when relevant actions occur

4 participants