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

[clickhouse] Use chrono::UTC for distributed_ddl_queue endpoint #7001

Merged
merged 6 commits into from
Nov 7, 2024
Merged
Show file tree
Hide file tree
Changes from 4 commits
Commits
File filter

Filter by extension

Filter by extension


Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
1 change: 1 addition & 0 deletions Cargo.lock

Some generated files are not rendered by default. Learn more about how customized files appear on GitHub.

3 changes: 2 additions & 1 deletion clickhouse-admin/src/clickhouse_cli.rs
Original file line number Diff line number Diff line change
Expand Up @@ -147,7 +147,8 @@ impl ClickhouseCli {
self.client_non_interactive(
ClickhouseClientType::Server,
format!(
"SELECT * FROM system.distributed_ddl_queue WHERE cluster = '{}' FORMAT JSONEachRow",
"SELECT * FROM system.distributed_ddl_queue WHERE cluster = '{}'
SETTINGS date_time_output_format = 'iso' FORMAT JSONEachRow",
OXIMETER_CLUSTER
).as_str(),
"Retrieve information about distributed ddl queries (ON CLUSTER clause)
Expand Down
1 change: 1 addition & 0 deletions clickhouse-admin/types/Cargo.toml
Original file line number Diff line number Diff line change
Expand Up @@ -12,6 +12,7 @@ anyhow.workspace = true
atomicwrites.workspace = true
camino.workspace = true
camino-tempfile.workspace = true
chrono.workspace = true
derive_more.workspace = true
itertools.workspace = true
omicron-common.workspace = true
Expand Down
22 changes: 12 additions & 10 deletions clickhouse-admin/types/src/lib.rs
Original file line number Diff line number Diff line change
Expand Up @@ -5,6 +5,7 @@
use anyhow::{bail, Context, Error, Result};
use atomicwrites::AtomicFile;
use camino::Utf8PathBuf;
use chrono::{DateTime, Utc};
use derive_more::{Add, AddAssign, Display, From};
use itertools::Itertools;
use omicron_common::api::external::Generation;
Expand Down Expand Up @@ -995,7 +996,7 @@ pub struct DistributedDdlQueue {
/// Settings used in the DDL operation
pub settings: BTreeMap<String, String>,
/// Query created time
pub query_create_time: String,
pub query_create_time: DateTime<Utc>,
/// Hostname
pub host: Ipv6Addr,
/// Host Port
Expand All @@ -1007,7 +1008,7 @@ pub struct DistributedDdlQueue {
/// Exception message
pub exception_text: String,
/// Query finish time
pub query_finish_time: String,
pub query_finish_time: DateTime<Utc>,
/// Duration of query execution (in milliseconds)
pub query_duration_ms: String,
Copy link
Collaborator

Choose a reason for hiding this comment

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

Looks like this is a UInt64, is it worth parsing into a stronger type during deserialization? Something like a Duration, or at least u64?

Copy link
Contributor Author

Choose a reason for hiding this comment

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

It's a string with a number in it :( I initially had it as a u64 and it didn't parse, but let me try with Duration!

Copy link
Collaborator

@bnaecker bnaecker Nov 6, 2024

Choose a reason for hiding this comment

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

Ah, this is because we're asking for JSON, and by default ClickHouse quotes 64-bit numbers. That causes serde to think it's a string, because it's written like "1", rather than just 1. You can set the output_format_json_quote_64bit_integers setting to ask it not to that.

Copy link
Contributor Author

Choose a reason for hiding this comment

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

Looks like Duration doesn't accept strings either :(

Copy link
Collaborator

Choose a reason for hiding this comment

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

See my earlier comment. You can ask CH not to quote big integers, so that serde can parse it just fine.

Copy link
Contributor Author

Choose a reason for hiding this comment

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

ugh sorry, GitHub hid that comment from me, I see it now thanks!

Copy link
Collaborator

Choose a reason for hiding this comment

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

No worries, I figured :) Just didn't want you to lose track of it. I think that will work, but it's honestly up to you if you want to apply it. I don't have context for what this all will be used for!

Copy link
Contributor Author

Choose a reason for hiding this comment

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

That worked, thanks! It's definitely better with strong types. Wasn't able to get Duration to parse but at least it's u64 now. We're going to use this endpoint (and others) for long term monitoring and debugging of the ClickHouse cluster.

}
Expand Down Expand Up @@ -1036,6 +1037,7 @@ impl DistributedDdlQueue {
mod tests {
use camino::Utf8PathBuf;
use camino_tempfile::Builder;
use chrono::{DateTime, Utc};
use slog::{o, Drain};
use slog_term::{FullFormat, PlainDecorator, TestStdoutWriter};
use std::collections::BTreeMap;
Expand Down Expand Up @@ -1809,8 +1811,8 @@ snapshot_storage_disk=LocalSnapshotDisk
fn test_distributed_ddl_queries_parse_success() {
let log = log();
let data =
"{\"entry\":\"query-0000000000\",\"entry_version\":5,\"initiator_host\":\"ixchel\",\"initiator_port\":22001,\"cluster\":\"oximeter_cluster\",\"query\":\"CREATE DATABASE IF NOT EXISTS db1 UUID 'a49757e4-179e-42bd-866f-93ac43136e2d' ON CLUSTER oximeter_cluster\",\"settings\":{\"load_balancing\":\"random\"},\"query_create_time\":\"2024-11-01 16:16:45\",\"host\":\"::1\",\"port\":22001,\"status\":\"Finished\",\"exception_code\":0,\"exception_text\":\"\",\"query_finish_time\":\"2024-11-01 16:16:45\",\"query_duration_ms\":\"4\"}
{\"entry\":\"query-0000000000\",\"entry_version\":5,\"initiator_host\":\"ixchel\",\"initiator_port\":22001,\"cluster\":\"oximeter_cluster\",\"query\":\"CREATE DATABASE IF NOT EXISTS db1 UUID 'a49757e4-179e-42bd-866f-93ac43136e2d' ON CLUSTER oximeter_cluster\",\"settings\":{\"load_balancing\":\"random\"},\"query_create_time\":\"2024-11-01 16:16:45\",\"host\":\"::1\",\"port\":22002,\"status\":\"Finished\",\"exception_code\":0,\"exception_text\":\"\",\"query_finish_time\":\"2024-11-01 16:16:45\",\"query_duration_ms\":\"4\"}
"{\"entry\":\"query-0000000000\",\"entry_version\":5,\"initiator_host\":\"ixchel\",\"initiator_port\":22001,\"cluster\":\"oximeter_cluster\",\"query\":\"CREATE DATABASE IF NOT EXISTS db1 UUID 'a49757e4-179e-42bd-866f-93ac43136e2d' ON CLUSTER oximeter_cluster\",\"settings\":{\"load_balancing\":\"random\"},\"query_create_time\":\"2024-11-01T16:16:45Z\",\"host\":\"::1\",\"port\":22001,\"status\":\"Finished\",\"exception_code\":0,\"exception_text\":\"\",\"query_finish_time\":\"2024-11-01T16:16:45Z\",\"query_duration_ms\":\"4\"}
{\"entry\":\"query-0000000000\",\"entry_version\":5,\"initiator_host\":\"ixchel\",\"initiator_port\":22001,\"cluster\":\"oximeter_cluster\",\"query\":\"CREATE DATABASE IF NOT EXISTS db1 UUID 'a49757e4-179e-42bd-866f-93ac43136e2d' ON CLUSTER oximeter_cluster\",\"settings\":{\"load_balancing\":\"random\"},\"query_create_time\":\"2024-11-01T16:16:45Z\",\"host\":\"::1\",\"port\":22002,\"status\":\"Finished\",\"exception_code\":0,\"exception_text\":\"\",\"query_finish_time\":\"2024-11-01T16:16:45Z\",\"query_duration_ms\":\"4\"}
"
.as_bytes();
let ddl = DistributedDdlQueue::parse(&log, data).unwrap();
Expand All @@ -1826,13 +1828,13 @@ snapshot_storage_disk=LocalSnapshotDisk
settings: BTreeMap::from([
("load_balancing".to_string(), "random".to_string()),
]),
query_create_time: "2024-11-01 16:16:45".to_string(),
query_create_time: "2024-11-01T16:16:45Z".parse::<DateTime::<Utc>>().unwrap(),
host: Ipv6Addr::from_str("::1").unwrap(),
port: 22001,
exception_code: 0,
exception_text: "".to_string(),
status: "Finished".to_string(),
query_finish_time: "2024-11-01 16:16:45".to_string(),
query_finish_time: "2024-11-01T16:16:45Z".parse::<DateTime::<Utc>>().unwrap(),
query_duration_ms: "4".to_string(),
},
DistributedDdlQueue{
Expand All @@ -1845,16 +1847,16 @@ snapshot_storage_disk=LocalSnapshotDisk
settings: BTreeMap::from([
("load_balancing".to_string(), "random".to_string()),
]),
query_create_time: "2024-11-01 16:16:45".to_string(),
query_create_time: "2024-11-01T16:16:45Z".parse::<DateTime::<Utc>>().unwrap(),
host: Ipv6Addr::from_str("::1").unwrap(),
port: 22002,
exception_code: 0,
exception_text: "".to_string(),
status: "Finished".to_string(),
query_finish_time: "2024-11-01 16:16:45".to_string(),
query_finish_time: "2024-11-01T16:16:45Z".parse::<DateTime::<Utc>>().unwrap(),
query_duration_ms: "4".to_string(),
},
];
];
assert!(ddl == expected_result);
}

Expand All @@ -1872,7 +1874,7 @@ snapshot_storage_disk=LocalSnapshotDisk
fn test_misshapen_distributed_ddl_queries_parse_fail() {
let log = log();
let data =
"{\"entry\":\"query-0000000000\",\"initiator_host\":\"ixchel\",\"initiator_port\":22001,\"cluster\":\"oximeter_cluster\",\"query\":\"CREATE DATABASE IF NOT EXISTS db1 UUID 'a49757e4-179e-42bd-866f-93ac43136e2d' ON CLUSTER oximeter_cluster\",\"settings\":{\"load_balancing\":\"random\"},\"query_create_time\":\"2024-11-01 16:16:45\",\"host\":\"::1\",\"port\":22001,\"status\":\"Finished\",\"exception_code\":0,\"exception_text\":\"\",\"query_finish_time\":\"2024-11-01 16:16:45\",\"query_duration_ms\":\"4\"}
"{\"entry\":\"query-0000000000\",\"initiator_host\":\"ixchel\",\"initiator_port\":22001,\"cluster\":\"oximeter_cluster\",\"query\":\"CREATE DATABASE IF NOT EXISTS db1 UUID 'a49757e4-179e-42bd-866f-93ac43136e2d' ON CLUSTER oximeter_cluster\",\"settings\":{\"load_balancing\":\"random\"},\"query_create_time\":\"2024-11-01T16:16:45Z\",\"host\":\"::1\",\"port\":22001,\"status\":\"Finished\",\"exception_code\":0,\"exception_text\":\"\",\"query_finish_time\":\"2024-11-01T16:16:45Z\",\"query_duration_ms\":\"4\"}
"
.as_bytes();
let result = DistributedDdlQueue::parse(&log, data);
Expand Down
6 changes: 4 additions & 2 deletions openapi/clickhouse-admin-server.json
Original file line number Diff line number Diff line change
Expand Up @@ -174,15 +174,17 @@
},
"query_create_time": {
"description": "Query created time",
"type": "string"
"type": "string",
"format": "date-time"
},
"query_duration_ms": {
"description": "Duration of query execution (in milliseconds)",
"type": "string"
},
"query_finish_time": {
"description": "Query finish time",
"type": "string"
"type": "string",
"format": "date-time"
},
"settings": {
"description": "Settings used in the DDL operation",
Expand Down
Loading