-
Notifications
You must be signed in to change notification settings - Fork 12
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
Basic implementation #3
Conversation
160c121
to
1219a9e
Compare
1219a9e
to
1ff37c5
Compare
bin/anycablebility
Outdated
#!/usr/bin/env ruby | ||
|
||
require 'bundler/setup' | ||
require 'docopt' |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Why did you choose docopt
? We can use OptionParse, which is a common practice. Also we can avoid the additional dependency.
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
I think that declarative approach is significant when it comes to building user interfaces. That's why I choose Docopt. It requires you to specify the actual help message that will be displayed to the end user to declare argument parsing rules.
Also we can avoid the additional dependency.
Docopt is relatively compact (16KB) and it has well-established API.
We can use OptionParse, which is a common practice.
Why is this important? Could you please expand on this?
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
-
I don't know any project that uses it
-
A lot of popular Ruby projects use OptionParser (Sidekiq, Rubocop to name a few)
-
It has not been maintained for a rather long time (https://ossert.evilmartians.io/docopt)
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
I don't know any project that uses it
A lot of popular Ruby projects use OptionParser (Sidekiq, Rubocop to name a few)
That's true: https://rubygems.org/gems/docopt/reverse_dependencies
It has not been maintained for a rather long time
https://ossert.evilmartians.io/docopt: Active Years Age: 4+ years
🤔
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
"Active Years Age" takes into an account issues and PRs. Yep, kind of confusing.
For the other hand, the commits history shows the real situation. As well as the state of open issues and PRs.
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
BTW the main Ossert application is to aggregate several metrics to come up to a more balanced grade of maintenance quality. So it is not very good to use one isolated metric to make your decision.
Anyway I'll try to find better name for "Active Years Age" in order to frustrate nobody.
lib/anycablebility/client.rb
Outdated
class Client | ||
attr_reader :state | ||
|
||
def initialize(cable_url, debug = false, ignore_message_types = []) |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Let's move debug
option into a general Anycablebility config.
We can also extract other options into a config and use it everywhere (e.g. Anycablebility.config.redis_url
, etc).
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
We can also extract other options into a config and use it everywhere (e.g. Anycablebility.config.redis_url, etc).
Should we use Anyway for this?
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Yep, it's already here.
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
I don't really understand what's the benefit of using Anyway for such task. I mean who will want to use Anycablebility inside a Rails app or configure it via environment variables?
I'm also not sure why should we introduce global state here instead of just passing config around. This makes no sense to represent our components as objects if they will rely on some global state, isn't it?
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Agree. Command line arguments would be enough.
Let's introduce a global Logger instead (say, Anycablebility.logger
). Or we can even use Anycable.logger
, btw.
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Let's introduce a global Logger instead (say, Anycablebility.logger). Or we can even use Anycable.logger, btw.
Could you please explain what goal do we want achieve with it? We want to config logger once, instead of configuring it in every component separately?
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
We want to config logger once, instead of configuring it in every component separately?
Exactly.
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
@palkan does the last commit satisfies this requirement?
lib/anycablebility/client.rb
Outdated
|
||
run_websocket_client | ||
|
||
Waiter.wait(20) { @state == :welcomed } |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
20 seconds? Maybe, 5 could be enough?
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Yup. Also, maybe we should make it configurable?
lib/anycablebility/client.rb
Outdated
attr_reader :state | ||
|
||
def initialize(cable_url, debug = false, ignore_message_types = []) | ||
@logger = Logger.new(debug ? STDOUT : '/dev/null') |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
It's better to use IO::NULL
instead of '/dev/null'
Before ``` App.new(options).run ``` After ``` App.new.run(options) ``` Makes more sense, doesn't it?
lib/anycablebility/cli/app.rb
Outdated
logger = Logger.new(STDOUT) | ||
logger.level = debug ? Logger::DEBUG : Logger::WARN | ||
|
||
rpc = Rpc.instance.configure(redis, debug, logger) |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
The purpose of the global/shared logger is to get rid of these parameters: debug
, logger
.
Let's do the following:
- introduce a
Logging
module:
module Anycablebility
module Logging
PREFIX = 'AC'
class << self
attr_writer :logger
end
def logger
Anycablebility.logger
end
# helper method
# later we'll be able to add a colorising here, depending on the level
def log(level, message)
return unless logger
logger.send(level.to_sym, PREFIX) { message }
end
end
end
- Then in
#run
method:
Anycablebility.logger = Logger.new(STDOUT).tap do |logger|
logger.level = debug ? Logger::DEBUG : Logger::WARN
end
- When configuring AnyCable:
Anycable.logger = Anycablebility.logger
- And anywhere you need a logger:
include Logging
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
# helper method # later we'll be able to add a colorising here, depending on the level def log(level, message) return unless logger logger.send(level.to_sym, PREFIX) { message } end
There's a Logger#formatter=
. Maybe we should take advantage of it for that purpose?
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
class << self attr_writer :logger end
Why do we need this? This is an attribute writer on Logging
itself. We need an attr_accessor :logger
on the Anycablebility
instead. Am I missing something?
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
There's a Logger#formatter=. Maybe we should take advantage of it for that purpose?
Great idea 👍
And we can do that later, let's skip for now.
attr_accessor :logger on the Anycablebility instead
Yep, you're right
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Done.
Could you please take a look at how I require stuff? I'm not sure I do it the right way. I have PHP background so I require components where do I need them, like PHP programmers use
their classes and constants. Is that right paradigm? Or we should make some kind of tree with require
s like rubocop does?
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Although this kind of global logger makes some parts of code less verbose but also less elegant. There's gotta be a practical yet elegant way of doing that.
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Could you please take a look at how I require stuff?
LGTM
Let's merge it and I'll play with it for a while and propose future improvements. |
@palkan let's discuss and list test cases to do. |
This is a basic implementation of concept of running RPC-server with the tests within single process. There are four simple tests that are implemented and tested on anycable-go 0.3.0. I need to get some feedback to understand am I going on the right direction or not. : )