[MM-35077] Add basic support for plugin intra-cluster communication (#17495)
* Add basic support for plugin intra-cluster communication * Some renaming for added clarity * Allow sending cluster event to specific nodes * Improve naming and documentation * Improve logging
Этот коммит содержится в:
коммит произвёл
GitHub
родитель
7dc1718c1d
Коммит
6af032d06a
@@ -1050,6 +1050,16 @@ type API interface {
|
||||
// @tag SlashCommand
|
||||
// Minimum server version: 5.28
|
||||
DeleteCommand(commandID string) error
|
||||
|
||||
// PublishPluginClusterEvent broadcasts a plugin event to all other running instances of
|
||||
// the calling plugin that are present in the cluster.
|
||||
//
|
||||
// This method is used to allow plugin communication in a High-Availability cluster.
|
||||
// The receiving side should implement the OnPluginClusterEvent hook
|
||||
// to receive events sent through this method.
|
||||
//
|
||||
// Minimum server version: 5.36
|
||||
PublishPluginClusterEvent(ev model.PluginClusterEvent, opts model.PluginClusterEventSendOptions) error
|
||||
}
|
||||
|
||||
var handshake = plugin.HandshakeConfig{
|
||||
|
||||
@@ -1113,3 +1113,10 @@ func (api *apiTimerLayer) DeleteCommand(commandID string) error {
|
||||
api.recordTime(startTime, "DeleteCommand", _returnsA == nil)
|
||||
return _returnsA
|
||||
}
|
||||
|
||||
func (api *apiTimerLayer) PublishPluginClusterEvent(ev model.PluginClusterEvent, opts model.PluginClusterEventSendOptions) error {
|
||||
startTime := timePkg.Now()
|
||||
_returnsA := api.apiImpl.PublishPluginClusterEvent(ev, opts)
|
||||
api.recordTime(startTime, "PublishPluginClusterEvent", _returnsA == nil)
|
||||
return _returnsA
|
||||
}
|
||||
|
||||
@@ -532,6 +532,40 @@ func (s *hooksRPCServer) ReactionHasBeenRemoved(args *Z_ReactionHasBeenRemovedAr
|
||||
return nil
|
||||
}
|
||||
|
||||
func init() {
|
||||
hookNameToId["OnPluginClusterEvent"] = OnPluginClusterEventID
|
||||
}
|
||||
|
||||
type Z_OnPluginClusterEventArgs struct {
|
||||
A *Context
|
||||
B model.PluginClusterEvent
|
||||
}
|
||||
|
||||
type Z_OnPluginClusterEventReturns struct {
|
||||
}
|
||||
|
||||
func (g *hooksRPCClient) OnPluginClusterEvent(c *Context, ev model.PluginClusterEvent) {
|
||||
_args := &Z_OnPluginClusterEventArgs{c, ev}
|
||||
_returns := &Z_OnPluginClusterEventReturns{}
|
||||
if g.implemented[OnPluginClusterEventID] {
|
||||
if err := g.client.Call("Plugin.OnPluginClusterEvent", _args, _returns); err != nil {
|
||||
g.log.Error("RPC call OnPluginClusterEvent to plugin failed.", mlog.Err(err))
|
||||
}
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
func (s *hooksRPCServer) OnPluginClusterEvent(args *Z_OnPluginClusterEventArgs, returns *Z_OnPluginClusterEventReturns) error {
|
||||
if hook, ok := s.impl.(interface {
|
||||
OnPluginClusterEvent(c *Context, ev model.PluginClusterEvent)
|
||||
}); ok {
|
||||
hook.OnPluginClusterEvent(args.A, args.B)
|
||||
} else {
|
||||
return encodableError(fmt.Errorf("Hook OnPluginClusterEvent called but not implemented."))
|
||||
}
|
||||
return nil
|
||||
}
|
||||
|
||||
type Z_RegisterCommandArgs struct {
|
||||
A *model.Command
|
||||
}
|
||||
@@ -4906,3 +4940,33 @@ func (s *apiRPCServer) DeleteCommand(args *Z_DeleteCommandArgs, returns *Z_Delet
|
||||
}
|
||||
return nil
|
||||
}
|
||||
|
||||
type Z_PublishPluginClusterEventArgs struct {
|
||||
A model.PluginClusterEvent
|
||||
B model.PluginClusterEventSendOptions
|
||||
}
|
||||
|
||||
type Z_PublishPluginClusterEventReturns struct {
|
||||
A error
|
||||
}
|
||||
|
||||
func (g *apiRPCClient) PublishPluginClusterEvent(ev model.PluginClusterEvent, opts model.PluginClusterEventSendOptions) error {
|
||||
_args := &Z_PublishPluginClusterEventArgs{ev, opts}
|
||||
_returns := &Z_PublishPluginClusterEventReturns{}
|
||||
if err := g.client.Call("Plugin.PublishPluginClusterEvent", _args, _returns); err != nil {
|
||||
log.Printf("RPC call to PublishPluginClusterEvent API failed: %s", err.Error())
|
||||
}
|
||||
return _returns.A
|
||||
}
|
||||
|
||||
func (s *apiRPCServer) PublishPluginClusterEvent(args *Z_PublishPluginClusterEventArgs, returns *Z_PublishPluginClusterEventReturns) error {
|
||||
if hook, ok := s.impl.(interface {
|
||||
PublishPluginClusterEvent(ev model.PluginClusterEvent, opts model.PluginClusterEventSendOptions) error
|
||||
}); ok {
|
||||
returns.A = hook.PublishPluginClusterEvent(args.A, args.B)
|
||||
returns.A = encodableError(returns.A)
|
||||
} else {
|
||||
return encodableError(fmt.Errorf("API PublishPluginClusterEvent called but not implemented."))
|
||||
}
|
||||
return nil
|
||||
}
|
||||
|
||||
@@ -35,6 +35,7 @@ const (
|
||||
UserHasBeenCreatedID = 17
|
||||
ReactionHasBeenAddedID = 18
|
||||
ReactionHasBeenRemovedID = 19
|
||||
OnPluginClusterEventID = 20
|
||||
TotalHooksID = iota
|
||||
)
|
||||
|
||||
@@ -209,4 +210,13 @@ type Hooks interface {
|
||||
//
|
||||
// Minimum server version: 5.30
|
||||
ReactionHasBeenRemoved(c *Context, reaction *model.Reaction)
|
||||
|
||||
// OnPluginClusterEvent is invoked when an intra-cluster plugin event is received.
|
||||
//
|
||||
// This is used to allow communication between multiple instances of the same plugin
|
||||
// that are running on separate nodes of the same High-Availability cluster.
|
||||
// This hook receives events sent by a call to PublishPluginClusterEvent.
|
||||
//
|
||||
// Minimum server version: 5.36
|
||||
OnPluginClusterEvent(c *Context, ev model.PluginClusterEvent)
|
||||
}
|
||||
|
||||
@@ -162,3 +162,9 @@ func (hooks *hooksTimerLayer) ReactionHasBeenRemoved(c *Context, reaction *model
|
||||
hooks.hooksImpl.ReactionHasBeenRemoved(c, reaction)
|
||||
hooks.recordTime(startTime, "ReactionHasBeenRemoved", true)
|
||||
}
|
||||
|
||||
func (hooks *hooksTimerLayer) OnPluginClusterEvent(c *Context, ev model.PluginClusterEvent) {
|
||||
startTime := timePkg.Now()
|
||||
hooks.hooksImpl.OnPluginClusterEvent(c, ev)
|
||||
hooks.recordTime(startTime, "OnPluginClusterEvent", true)
|
||||
}
|
||||
|
||||
@@ -2682,6 +2682,20 @@ func (_m *API) PluginHTTP(request *http.Request) *http.Response {
|
||||
return r0
|
||||
}
|
||||
|
||||
// PublishPluginClusterEvent provides a mock function with given fields: ev, opts
|
||||
func (_m *API) PublishPluginClusterEvent(ev model.PluginClusterEvent, opts model.PluginClusterEventSendOptions) error {
|
||||
ret := _m.Called(ev, opts)
|
||||
|
||||
var r0 error
|
||||
if rf, ok := ret.Get(0).(func(model.PluginClusterEvent, model.PluginClusterEventSendOptions) error); ok {
|
||||
r0 = rf(ev, opts)
|
||||
} else {
|
||||
r0 = ret.Error(0)
|
||||
}
|
||||
|
||||
return r0
|
||||
}
|
||||
|
||||
// PublishUserTyping provides a mock function with given fields: userID, channelId, parentId
|
||||
func (_m *API) PublishUserTyping(userID string, channelId string, parentId string) *model.AppError {
|
||||
ret := _m.Called(userID, channelId, parentId)
|
||||
|
||||
@@ -194,6 +194,11 @@ func (_m *Hooks) OnDeactivate() error {
|
||||
return r0
|
||||
}
|
||||
|
||||
// OnPluginClusterEvent provides a mock function with given fields: c, ev
|
||||
func (_m *Hooks) OnPluginClusterEvent(c *plugin.Context, ev model.PluginClusterEvent) {
|
||||
_m.Called(c, ev)
|
||||
}
|
||||
|
||||
// ReactionHasBeenAdded provides a mock function with given fields: c, reaction
|
||||
func (_m *Hooks) ReactionHasBeenAdded(c *plugin.Context, reaction *model.Reaction) {
|
||||
_m.Called(c, reaction)
|
||||
|
||||
Ссылка в новой задаче
Block a user