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

Introduce server plugin helpers #1312

Merged
merged 29 commits into from
Nov 28, 2016

Conversation

tagomoris
Copy link
Member

@tagomoris tagomoris commented Nov 15, 2016

Server plugin helpers are to make plugin authors to write network servers very easily.
These make authors free from writing code to create sockets, handle event loops or threads.

The key features are:

  • callback-based network daemon execution (plugin helper style)
  • test driver support to wait startup/shutdown servers before actual test code running
  • creating sockets via socket manager in default for coming multi-process configuration support

The full features of socket/server plugin helpers and TBDs are:

  • TCP, UDP and TLS support (TLS will be implemented in future change)
  • TCP/TLS keepalive (in future)
  • IPv6 support

I committed all changes for this pull-request

  • server plugin helper: TCP/UDP implementation complete
  • tcp/udp input plugin: migrated to v0.14 APIs with server plugin helper
  • forward input plugin: updated with server plugin helper
  • tests of server plugin helper

To reduce the size of diff, keepalive support and socket plugin helper support will be implemented in following pull requests.

  • socket plugin helper and its tests
  • update of output plugins using sockets (including out_forward)
  • http input plugin update (in future with keepalive support)

@tagomoris
Copy link
Member Author

@repeatedly Could you take a look for API design and basic features? If you are ok, I'll write tests and move forward to implement socket plugin helper.

router.emit(tag, time, record)
option = msg[3]
end

# return option for response
option
ensure
p(here: "ensure of on_message", error: $!) if $!
Copy link
Member

Choose a reason for hiding this comment

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

Why use p?

Copy link
Member Author

Choose a reason for hiding this comment

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

It's just about debugging. I missed to remote it.

end

class TCPServerHandler < Coolio::TCPSocket
PEERADDR_FAILED = ["?", "?", "name resolusion failed", "?"]
Copy link
Member

Choose a reason for hiding this comment

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

No use in new implementation.

end

def initialize(sock, resolve_name, max_bytes, flags, log, under_plugin_development, &callback)
raise ArgumentError, "socket is a UDPSocket" unless sock.is_a?(UDPSocket)
Copy link
Member

Choose a reason for hiding this comment

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

socket must be a UDPSocket: socket = #{sock} or socket is not a UDPSocket: socket = #{sock} is better.

@repeatedly
Copy link
Member

Basic implementation looks good.

Off topic: How about moving under_plugin_development into Engine like Engine.under_plugin_development?
Passing under_plugin_development to each method seems bit messy...

def on_read_without_connection(data)
@data_callback.call(data)
rescue => e
p(here: "error without connection", error: e)
Copy link
Member

Choose a reason for hiding this comment

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

p debug.

def on_read_with_connection(data)
@data_callback.call(data, self)
rescue => e
p(here: "error with connection", error: e)
Copy link
Member

Choose a reason for hiding this comment

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

ditto

@tagomoris tagomoris force-pushed the introduce-socket-server-plugin-helpers branch from 57e1c9f to a8a6ccc Compare November 16, 2016 09:15
@tagomoris
Copy link
Member Author

@repeatedly No way. It's very bad practice to use Engine for such purpose. Engine is a singleton object, and using Engine for such purpose makes many messy code to overriding Engine.under_plugin_development? and to revert overriding in tests.

@tagomoris tagomoris force-pushed the introduce-socket-server-plugin-helpers branch from a8a6ccc to fe38634 Compare November 16, 2016 09:24
@tagomoris
Copy link
Member Author

I pushed updated commits to follow review comments, and add some changes:

  • add Fluent::PluginHelper::Server::EventHandler module and added TCPServer/UDPServer under it
  • add Fluent::PluginHelper::Server::CallbackSocket and its subclasses of it for tcp/udp

I changed to pass an instance object of CallbackSocket to callbacks, to avoid to pass instances of cool.io classes. If plugin helper passes instances of cool.io classes, users may use methods of these classes (even if we want to keep these methods as semi-private).
For instances of original classes, we can control the variations of these methods (for compatibility).

@tagomoris
Copy link
Member Author

There's no change about server plugin helper API for plugins in updated commits.

@tagomoris tagomoris force-pushed the introduce-socket-server-plugin-helpers branch 3 times, most recently from a364153 to b6565b7 Compare November 21, 2016 11:49
@tagomoris tagomoris changed the title [WIP] Introduce socket/server plugin helpers [WIP] Introduce server plugin helpers Nov 21, 2016
@tagomoris tagomoris force-pushed the introduce-socket-server-plugin-helpers branch from b6565b7 to 722c9b6 Compare November 22, 2016 01:54
@tagomoris
Copy link
Member Author

I pushed all commits to add/fix server plugin helper, and tests which pass on my laptop.
I'll check CI failure and fix it, but anyway, @repeatedly could you review this change?

@tagomoris tagomoris changed the title [WIP] Introduce server plugin helpers Introduce server plugin helpers Nov 22, 2016
@tagomoris tagomoris force-pushed the introduce-socket-server-plugin-helpers branch from d563fa5 to aaaaa1c Compare November 22, 2016 06:52
desc 'The payload is read up to this character.'
config_param :delimiter, :string, default: "\n" # syslog family add "\n" to each message and this seems only way to split messages in tcp stream

def listen(callback)
log.info "listening tcp socket on #{@bind}:#{@port}"
def configure(conf)
Copy link
Member

Choose a reason for hiding this comment

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

should check source_host_key and source_hostname_key?

if !@source_host_key.nil? && @source_hostname_key.nil?
  @source_hostname_key  = @source_host_key
end

Copy link
Member Author

Choose a reason for hiding this comment

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

Right.

tag = extract_tag_from_record(record)
tag ||= @tag
time ||= extract_time_from_record(record) || Fluent::EventTime.now
record[@source_host_key] = conn.remote_host if @source_host_key
Copy link
Member

Choose a reason for hiding this comment

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

use @source_hostname_key instead.

tag = extract_tag_from_record(record)
tag ||= @tag
time ||= extract_time_from_record(record) || Fluent::EventTime.now
record[@source_host_key] = sock.remote_host if @source_host_key
Copy link
Member

Choose a reason for hiding this comment

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

ditto


attr_reader :_event_loop # for tests

def event_loop_attach(watcher)
@_event_loop_mutex.synchronize do
@_event_loop.attach(watcher)
@_event_loop_attached_watchers << watcher
Copy link
Member

Choose a reason for hiding this comment

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

This means Loop#watchers sometimes returns incorrect watchers?

Copy link
Member Author

Choose a reason for hiding this comment

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

Loop#watchers contains watchers which are NOT registered by event loop helpers, like TCP connection I/O watchers registered by TCP server watcher.
These watchers should be detached/closed by these watchers itself. Detaching such watchers by event loop helpers forcedly makes troubles.

when :data
@sock.data(&callback)
when :write_complete
cb = ->(){
Copy link
Member

Choose a reason for hiding this comment

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

Use one line for :close code.

SOCK_OPT_FORMAT = 'I!I!' # { int l_onoff; int l_linger; }

def initialize(sock, close_callback, resolve_name, linger_timeout, log, under_plugin_development, connect_callback)
raise ArgumentError, "socket must be a TCPSocket" unless sock.is_a?(TCPSocket)
Copy link
Member

Choose a reason for hiding this comment

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

add : sock = #{sock} to show actual object.

@tagomoris tagomoris force-pushed the introduce-socket-server-plugin-helpers branch from a7f83ce to 0e6c4ea Compare November 22, 2016 08:58
@tagomoris tagomoris force-pushed the introduce-socket-server-plugin-helpers branch from 08d2360 to 4e63ef4 Compare November 28, 2016 06:33
@tagomoris tagomoris merged commit c5c8709 into master Nov 28, 2016
@ganmacs ganmacs deleted the introduce-socket-server-plugin-helpers branch July 11, 2019 07:59
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment
Labels
Projects
None yet
Development

Successfully merging this pull request may close these issues.

3 participants