Julio Biason
3 years ago
9 changed files with 1550 additions and 0 deletions
File diff suppressed because it is too large
Load Diff
@ -0,0 +1,13 @@
|
||||
[package] |
||||
name = "notifytest" |
||||
version = "0.1.0" |
||||
edition = "2021" |
||||
|
||||
# See more keys and their definitions at https://doc.rust-lang.org/cargo/reference/manifest.html |
||||
|
||||
[dependencies] |
||||
clap = { version = "3.0.13", features = ["derive", "env"] } |
||||
env_logger = "0.9.0" |
||||
log = "0.4.14" |
||||
sqlx = { version = "0.5.10", features = ["runtime-tokio-rustls", "postgres", "migrate", "macros"] } |
||||
tokio = { version = "1.16.1", features = ["rt", "net", "macros", "io-util"] } |
@ -0,0 +1,3 @@
|
||||
# NotifyTest |
||||
|
||||
Testing Postgres notification features |
@ -0,0 +1,50 @@
|
||||
CREATE TABLE targets ( |
||||
level_1 TEXT, |
||||
level_2 TEXT, |
||||
channel_name TEXT, |
||||
UNIQUE (level_1, level_2) |
||||
); |
||||
|
||||
CREATE TABLE commands ( |
||||
id SERIAL PRIMARY KEY, |
||||
level_1 TEXT, |
||||
level_2 TEXT, |
||||
payload TEXT, |
||||
channel_name TEXT, |
||||
channel_failure BOOLEAN |
||||
); |
||||
|
||||
CREATE OR REPLACE FUNCTION notify_channel() |
||||
RETURNS TRIGGER |
||||
LANGUAGE PLPGSQL |
||||
AS |
||||
$$ |
||||
DECLARE |
||||
target_channel TEXT; |
||||
BEGIN |
||||
SELECT channel_name |
||||
INTO target_channel |
||||
FROM targets |
||||
WHERE level_1 = NEW.level_1 |
||||
AND level_2 = NEW.level_2; |
||||
|
||||
if found then |
||||
SELECT pg_notify(target_channel, NEW.playload); |
||||
UPDATE commands |
||||
SET channel_name = channel_name, channel_failure = false |
||||
WHERE id = NEW.id; |
||||
else |
||||
UPDATE commands |
||||
SET channel_failure = true |
||||
WHERE id = NEW.id; |
||||
end if; |
||||
|
||||
RETURN NEW; |
||||
END; |
||||
$$; |
||||
|
||||
CREATE TRIGGER notify_channel |
||||
AFTER INSERT |
||||
ON commands |
||||
FOR EACH ROW |
||||
EXECUTE PROCEDURE notify_channel(); |
@ -0,0 +1,29 @@
|
||||
CREATE OR REPLACE FUNCTION notify_channel() |
||||
RETURNS TRIGGER |
||||
LANGUAGE PLPGSQL |
||||
AS |
||||
$$ |
||||
DECLARE |
||||
target_channel TEXT; |
||||
BEGIN |
||||
SELECT channel_name |
||||
INTO target_channel |
||||
FROM targets |
||||
WHERE level_1 = NEW.level_1 |
||||
AND level_2 = NEW.level_2; |
||||
|
||||
if found then |
||||
SELECT pg_notify(target_channel, NEW.payload); |
||||
UPDATE commands |
||||
SET channel_name = channel_name, channel_failure = false |
||||
WHERE id = NEW.id; |
||||
else |
||||
UPDATE commands |
||||
SET channel_failure = true |
||||
WHERE id = NEW.id; |
||||
end if; |
||||
|
||||
RETURN NEW; |
||||
END; |
||||
$$; |
||||
|
@ -0,0 +1,28 @@
|
||||
CREATE OR REPLACE FUNCTION notify_channel() |
||||
RETURNS TRIGGER |
||||
LANGUAGE PLPGSQL |
||||
AS |
||||
$$ |
||||
DECLARE |
||||
target_channel TEXT; |
||||
BEGIN |
||||
SELECT channel_name |
||||
INTO target_channel |
||||
FROM targets |
||||
WHERE level_1 = NEW.level_1 |
||||
AND level_2 = NEW.level_2; |
||||
|
||||
if found then |
||||
SELECT pg_notify(target_channel, NEW.payload); |
||||
UPDATE commands |
||||
SET channel_name = channel_name, channel_failure = false |
||||
WHERE id = NEW.id; |
||||
else |
||||
UPDATE commands |
||||
SET channel_failure = true |
||||
WHERE id = NEW.id; |
||||
end if; |
||||
END; |
||||
$$; |
||||
|
||||
|
@ -0,0 +1,26 @@
|
||||
CREATE OR REPLACE FUNCTION notify_channel() |
||||
RETURNS TRIGGER |
||||
LANGUAGE PLPGSQL |
||||
AS |
||||
$$ |
||||
DECLARE |
||||
target_channel TEXT; |
||||
BEGIN |
||||
SELECT channel_name |
||||
INTO target_channel |
||||
FROM targets |
||||
WHERE level_1 = NEW.level_1 |
||||
AND level_2 = NEW.level_2; |
||||
|
||||
if found then |
||||
PERFORM pg_notify(target_channel, NEW.payload); |
||||
UPDATE commands |
||||
SET channel_name = channel_name, channel_failure = false |
||||
WHERE id = NEW.id; |
||||
else |
||||
UPDATE commands |
||||
SET channel_failure = true |
||||
WHERE id = NEW.id; |
||||
end if; |
||||
END; |
||||
$$; |
@ -0,0 +1,29 @@
|
||||
CREATE OR REPLACE FUNCTION notify_channel() |
||||
RETURNS TRIGGER |
||||
LANGUAGE PLPGSQL |
||||
AS |
||||
$$ |
||||
DECLARE |
||||
target_channel TEXT; |
||||
BEGIN |
||||
SELECT channel_name |
||||
INTO target_channel |
||||
FROM targets |
||||
WHERE level_1 = NEW.level_1 |
||||
AND level_2 = NEW.level_2; |
||||
|
||||
if found then |
||||
PERFORM pg_notify(target_channel, NEW.payload); |
||||
UPDATE commands |
||||
SET channel_name = channel_name, channel_failure = false |
||||
WHERE id = NEW.id; |
||||
else |
||||
UPDATE commands |
||||
SET channel_failure = true |
||||
WHERE id = NEW.id; |
||||
end if; |
||||
|
||||
RETURN NEW; |
||||
END; |
||||
$$; |
||||
|
@ -0,0 +1,57 @@
|
||||
use clap::Parser; |
||||
use sqlx::postgres::PgListener; |
||||
use sqlx::postgres::PgPoolOptions; |
||||
use sqlx::postgres::Postgres; |
||||
use sqlx::Pool; |
||||
|
||||
async fn connect(url: &str) -> Pool<Postgres> { |
||||
PgPoolOptions::new() |
||||
.max_connections(3) |
||||
.connect(url) |
||||
.await |
||||
.expect("Failed to connect to the database") |
||||
} |
||||
|
||||
async fn create_listener(channel: &str, url: &str) { |
||||
let mut listener = PgListener::connect(&url) |
||||
.await |
||||
.expect("Failed to connect listener {channel}"); |
||||
listener |
||||
.listen(channel) |
||||
.await |
||||
.expect("Failed to listen to channel {channel}"); |
||||
|
||||
log::info!("Listener on {channel} ready..."); |
||||
loop { |
||||
let notification = listener |
||||
.recv() |
||||
.await |
||||
.expect("Failed to receive data from channel {channel}"); |
||||
log::info!("Notification: {:?}", notification); |
||||
} |
||||
} |
||||
|
||||
#[derive(Parser)] |
||||
#[clap(version, about)] |
||||
struct Args { |
||||
/// URL for the database connection.
|
||||
#[clap(short, long, env = "DATABASE_URL")] |
||||
database: String, |
||||
} |
||||
|
||||
#[tokio::main] |
||||
async fn main() { |
||||
env_logger::init(); |
||||
let args = Args::parse(); |
||||
let pool = connect(&args.database).await; |
||||
sqlx::migrate!() |
||||
.run(&pool) |
||||
.await |
||||
.expect("Migration failure"); |
||||
|
||||
let listener_type_1 = create_listener("type_1", &args.database); |
||||
let listener_type_2 = create_listener("type_2", &args.database); |
||||
let listener_type_3 = create_listener("type_3", &args.database); |
||||
|
||||
tokio::join!(listener_type_1, listener_type_2, listener_type_3); |
||||
} |
Loading…
Reference in new issue