Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Feat: Add redis backend #813

Open
wants to merge 19 commits into
base: master
Choose a base branch
from
Open

Conversation

p1gp1g
Copy link

@p1gp1g p1gp1g commented Dec 19, 2024

Currently, autopush requires using Bigtable, there is no particular issue for a big, public server, but some may want to host their own server, or to do some tests locally. So this PR adds another kind of backend using Redis. It should work with redis forks too.

It mostly follow the behavior of bigtable with a few differences:

  • when saving a message with a topic, it simply removes the previous message for this topic. So topic messages and timestamp messages are processed the exact same way. Therefore the test (run_gauntlet) is a bit different for this: it adds 2 messages for the same topic and check only one is fetched.
  • Timestamps used and returned by fetch_timestamp_messages are the date of the record in ms, with bigtables it uses the message's sortkey_timestamp, in seconds.

I've also added a docker-compose file to run everything.

For the moment RedisClientImpl doesn't use connection pooling, but this should be easily implemented, it also provide the Command trait, returned by RedisClientImpl.connection

Fixes #774

Copy link
Member

@jrconlin jrconlin left a comment

Choose a reason for hiding this comment

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

Gotta admit, Redis is not really the DB that I would have picked for this, but sure, provided that the durable storage element is set, it should be able to handle light loads.

FWIW, I had done a version that used Postgres a long time ago. (If you go through the Changelog, you might find a reference to it.) Sadly, I burned that branch a while ago.

Still, thank you for this. There are a few things you'll need to do to fix it up.

The requirements are:

  • Please don't use .unwrap() (or if you do, please explain why.)
  • We actually do need to support topic messages.
  • (Make sure that all unit and integration tests pass)

autoendpoint/src/server.rs Outdated Show resolved Hide resolved
@@ -1,5 +1,5 @@
pub fn main() {
if !cfg!(feature = "bigtable") {
panic!("No database defined! Please compile with `features=bigtable`");
if !cfg!(feature = "bigtable") && !cfg!(feature = "redis") {
Copy link
Member

Choose a reason for hiding this comment

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

bigtable and redis are conflicting feature flags, no?

If you like, we do a conditional check in syncstorage-rs to prevent folk from accidentally specifying both flags.

Copy link
Author

Choose a reason for hiding this comment

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

They should not be conflicting, the server is selected with the dsn url

autopush-common/src/db/redis/redis_client/mod.rs Outdated Show resolved Hide resolved
autopush-common/src/db/redis/redis_client/mod.rs Outdated Show resolved Hide resolved
autopush-common/src/db/redis/redis_client/mod.rs Outdated Show resolved Hide resolved
autopush-common/src/db/redis/redis_client/mod.rs Outdated Show resolved Hide resolved
/**
Topic messages are handled as other messages with redis, we return nothing.
*/
async fn fetch_topic_messages(
Copy link
Member

Choose a reason for hiding this comment

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

Oof, yeah, no.

These need to return topic messages. Topics are messages that replace pending versions. (You will only ever get back one topic message, but you will get back all the prior versions of regular messages.)

What this does is throw away topic messages.

Basically, the integration tests are going to have a fit when they try running against this, so it needs to work correctly.

Copy link
Author

Choose a reason for hiding this comment

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

Topic messages are replaced and only the last version is kept. See comment bellow

autopush-common/src/db/redis/redis_client/mod.rs Outdated Show resolved Hide resolved
autopush-common/src/notification.rs Show resolved Hide resolved
docker-compose.yml Outdated Show resolved Hide resolved
@p1gp1g
Copy link
Author

p1gp1g commented Dec 21, 2024

Thank you for the review, I've addressed most of the comments.

I went to redis, because this is also what I used for Uppush, which also work as a webpush server. I've seen in the issue comments you had a version with Postgres.

Regarding the topics, this implementation supports topic, but in another way. See the tests: we store 2 messages with the same topic and fetch a single one (if I set topic to None, it fails)

        // We store 2 messages, with a single topic
        let test_notification_0 = crate::db::Notification {
            channel_id: topic_chid,
            version: "version0".to_owned(),
            ttl: 300,
            topic: Some("topic".to_owned()),
            timestamp,
            data: Some(test_data.clone()),
            sortkey_timestamp: Some(sort_key),
            ..Default::default()
        };
        assert!(client
            .save_message(&uaid, test_notification_0.clone())
            .await
            .is_ok());

        let test_notification = crate::db::Notification {
            timestamp: now(),
            version: "version1".to_owned(),
            sortkey_timestamp: Some(sort_key + 10),
            ..test_notification_0
        };

        assert!(client
            .save_message(&uaid, test_notification.clone())
            .await
            .is_ok());

        let mut fetched = client.fetch_timestamp_messages(&uaid, None, 999).await?;
        assert_eq!(fetched.messages.len(), 1);

By the way, using the current chidmessageid allows to do this automatically, the topic isn't necessary: ddc8a46

Regarding the tests, they all pass cargo test --no-default-features --features redis

@jrconlin
Copy link
Member

jrconlin commented Jan 7, 2025

Sigh, just like the other PR, I'm afraid we can't accept this PR with unsigned commits. Please feel free to resubmit this with signed commits.

(This is a policy put in place by our Security Operations team.)

@p1gp1g
Copy link
Author

p1gp1g commented Jan 7, 2025

All the commits are signed

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment
Labels
None yet
Projects
None yet
Development

Successfully merging this pull request may close these issues.

Using autopush with local database (like sqlite)
2 participants