Skip to content
This repository has been archived by the owner on Aug 25, 2021. It is now read-only.

Implement configuration #15

Merged
merged 21 commits into from
Apr 8, 2019
Merged

Implement configuration #15

merged 21 commits into from
Apr 8, 2019

Conversation

Kirguir
Copy link
Contributor

@Kirguir Kirguir commented Jan 31, 2019

Implement a layer that implements the configuration of the application and provides the means to work with it.

@Kirguir Kirguir self-assigned this Jan 31, 2019
@Kirguir Kirguir added feature New feature or request k::design Related to overall design and/or architecture k::config Related to application configuration labels Jan 31, 2019
@Kirguir Kirguir added this to the 0.1.0 milestone Jan 31, 2019
@Kirguir
Copy link
Contributor Author

Kirguir commented Jan 31, 2019

@alexlapa напишите, пожалуйста, какие параметры нужны в конфиге, как будут задаваться (файл, env) и значения по-умолчанию, если нужны.

@alexlapa
Copy link
Collaborator

@Kirguir ,

В сорцах стоят дефолтные значения, переопределяются они через конфигурационный файл или через переменные среды. А вот по приоритету config / env var уже не так очевидно. Я бы вообще просто панику бросал, если одна и та-же переменная прокидывается и через конфиг и через окружение и с разными значениями. Как в SAPI было сделано? env var > config?

По поводу конкретных параметров сейчас мудрить смысла не вижу - они в процессе сами будут появляться. Например, HEARTBEAT_INTERVAL и CLIENT_TIMEOUT из #15 .

@alexlapa alexlapa mentioned this pull request Jan 31, 2019
16 tasks
@Kirguir Kirguir requested a review from alexlapa March 22, 2019 14:42
…me, add basic makefile, add config tests, add duration serde tests
@alexlapa alexlapa changed the title WIP: Implements configuration WIP: Implement configuration Mar 25, 2019
@alexlapa
Copy link
Collaborator

@tyranron ,

Гляньте, пожалуйста, будут ли у Вас замечания по реализации. Документацию добавлю после, и тогда уже попрошу полное ревью.

@alexlapa alexlapa requested a review from tyranron March 29, 2019 13:25
Copy link
Member

@tyranron tyranron left a comment

Choose a reason for hiding this comment

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

The overall impression that code may be simplified.

Consider to use structopt for command line.

Wrapping into untyped config::Config for merging is also a bit strange. Can't this be achieved without that?

Cargo.toml Outdated
futures = "0.1"
hashbrown = "0.1"
humantime = "1.2.0"
Copy link
Member

Choose a reason for hiding this comment

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

There is no sense to specify patch version due to work of default carret requirement.

Just humantime = "1.2" is enough.

src/conf/mod.rs Outdated
};
use failure::Error;
use serde_derive::{Deserialize, Serialize};
use std::collections::HashMap;
Copy link
Member

Choose a reason for hiding this comment

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

Do not forget to separate std imports .

fn default() -> Self {
Self {
bind_ip: IpAddr::V4(Ipv4Addr::new(0, 0, 0, 0)),
bind_port: 8080,
Copy link
Member

Choose a reason for hiding this comment

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

Consider to use smart-default. It's way more ergonomic.


impl Server {
pub fn get_bind_addr(&self) -> impl std::net::ToSocketAddrs {
(self.bind_ip, self.bind_port)
Copy link
Member

Choose a reason for hiding this comment

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

Why returning impl? It has no sense in this context. It's almost always to return a concrete type rather then it's abstraction. So, just (IpAddr, u16) is enough.

Copy link
Collaborator

Choose a reason for hiding this comment

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

@tyranron ,

Если можно вернуть интерфейс - нужно возвращать интерфейс. Просто хороший тон. Но, не принципиально, на самом деле.

Copy link
Member

Choose a reason for hiding this comment

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

@Kirguir why this is a good tone? It just erases additional type information. "Expect wider type, but return concrete type".

Copy link
Collaborator

Choose a reason for hiding this comment

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

@tyranron ,

Абстракции, инкапсуляция, loose coupling, все дела.

Copy link
Member

Choose a reason for hiding this comment

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

@alexlapa hmm... I agree. I this context it allows to hide the inner representation of the Server, which makes sense in the usage places where we require just ToSocketAddrs.

Cargo.toml Outdated
serde = { version = "1.0", features = ["derive"] }
serde_derive = "1.0"
Copy link
Member

Choose a reason for hiding this comment

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

Why add serde_derive again when the next line above contains features = ["derive"]?

E: de::Error,
{
let dur = humantime::parse_duration(value).map_err(|_| {
de::Error::invalid_value(Unexpected::Str(value), &self)
Copy link
Member

Choose a reason for hiding this comment

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

Wow, this seems tough. This should be implemented in some util module, or even a separate crate.

Fortunately, reading documentation carefully allows to avoid writing redudant code: serde-humantime 🙃

Copy link
Collaborator

Choose a reason for hiding this comment

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

@tyranron ,

Прикрутил, но там только deserialize. А serialize используется в этом финте, который там не от хорошей жизни. Получится выкосить его - выкошу serialize.

Copy link
Member

Choose a reason for hiding this comment

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

@alexlapa I think we should anyway have Serialize capability, even for debug purposes, like "export me the current config".

A bit more exploring and we have this.

src/conf/mod.rs Outdated
/// - configuration file, the name of which is given as a command line
/// parameter or environment variable;
/// - environment variables;
pub fn new() -> Result<Self, Error> {
Copy link
Member

Choose a reason for hiding this comment

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

I guess parse() is a better name here.

};

use super::*;
use crate::conf::server::Server;
Copy link
Member

Choose a reason for hiding this comment

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

This is not very ergonomic due to know how conf module is layouted. It's better to re-export stuff in conf, so I can just do conff::Server.

@alexlapa
Copy link
Collaborator

@tyranron ,

Вы, помнится, заметили, что, вроде бы, вот этот кусок:

    let mut cfg = Config::new();
    cfg.merge(Self::default())?;
    let s: Self = cfg.try_into()?;

можно реализовать корректнее. Напомните, пожалуйста, каким образом.

@tyranron
Copy link
Member

tyranron commented Mar 30, 2019

@alexlapa nope, I've investigated a config crate and its examples a bit further, and it's seems that this the idiomatic and correct way. I think my confusion goes from Go experience.

However, as far as I found, we may omit config::Source implementation by doing:

let mut cfg = Config::try_from(&Self::default())?;

which requires only Serialize on T.

@alexlapa
Copy link
Collaborator

alexlapa commented Apr 1, 2019

@tyranron ,

let mut cfg = Config::try_from(&Self::default())?;

А это то, о чем говорил Kirguir . Там, в нутре config::Config, есть две HashMap'ы: defaults и overrides. Config::try_from пишет в overrides и последующие Config::merge эти значения не обновляют.

@alexlapa
Copy link
Collaborator

alexlapa commented Apr 1, 2019

@tyranron ,

Изучил structopt. Без дополнительной обработки напильником structopt и config-rs не дружат. structopt умеет arg, env vars. config-rs умеет в file, env vars. Если мы хотим чтобы args были наиболее приоритетными (args>env>file>default), то мержить надо ручками. Предлагаю просто дождаться пока config-rs интегрируют clap, issue тут. А пока сможем и без передачи конфига через args пожить. Ну или можно сделать (file>args>env>>default), что, в общем, тоже не плохо.

@tyranron
Copy link
Member

tyranron commented Apr 2, 2019

@alexlapa

А это то, о чем говорил Kirguir . Там, в нутре config::Config, есть две HashMap'ы: defaults и overrides. Config::try_from пишет в overrides и последующие Config::merge эти значения не обновляют.

meh... 😕

OK, now the current implementation is OK. Later, I'll fix the issue in config-rs when will mess with it in my project.

Изучил structopt. Без дополнительной обработки напильником structopt и config-rs не дружат. structopt умеет arg, env vars. config-rs умеет в file, env vars. Если мы хотим чтобы args были наиболее приоритетными (args>env>file>default), то мержить надо ручками. Предлагаю просто дождаться пока config-rs интегрируют clap, issue тут. А пока сможем и без передачи конфига через args пожить. Ну или можно сделать (file>args>env>>default), что, в общем, тоже не плохо.

Agree, for now we can skip it. Changing the priorities i not the solution.

@alexlapa alexlapa requested a review from tyranron April 2, 2019 14:15
Copy link
Member

@tyranron tyranron left a comment

Choose a reason for hiding this comment

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

  • A little refactoring is done to simplify code more and make tests more BDD'ish.
  • Removed unused dependencies.
  • Refactored Makefile to throw away Docker squats.

Do not forget about FCM.

FCM:

Create application configuration (#15)

- impl conf module which holds typed configuration of application
- parse configuration from file and env vars
- allow to specify configuration file path
- refactor existing code to use values from configuration options

@Kirguir Kirguir changed the title WIP: Implement configuration Implement configuration Apr 8, 2019
@Kirguir Kirguir merged commit a004d67 into master Apr 8, 2019
@Kirguir Kirguir deleted the add_config branch April 8, 2019 07:23
Sign up for free to subscribe to this conversation on GitHub. Already have an account? Sign in.
Labels
feature New feature or request k::config Related to application configuration k::design Related to overall design and/or architecture
Projects
None yet
Development

Successfully merging this pull request may close these issues.

3 participants