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

Plugin architecture #14

Closed
graup opened this issue Nov 21, 2018 · 4 comments
Closed

Plugin architecture #14

graup opened this issue Nov 21, 2018 · 4 comments
Assignees
Labels
help wanted Extra attention is needed proposal
Milestone

Comments

@graup
Copy link
Member

graup commented Nov 21, 2018

This is a proposal to implement a plugin architecture for aergosvr.

Why plugins?

  • non-essential features that not every user needs and private logic
  • don't bloat the core codebase → easier to maintain, smaller binary
  • more direct access than external code has
  • can reuse types and utils

What features does a plugin need?

Apart from registering plugins, we will need some additional features in the core.

  • register and init
  • high level:
    • subscribe to events, e.g. new block (also, contract events after they get implemented)
    • request data, e.g. hub.RequestFuture(message.ChainSvc, &message.GetBlockByNo{BlockNo: i})
  • low level:
    • actor middleware, e.g. for tracing

Plugins could just be actors, that way they could even change some existing behaviors instead of just adding features.

Example use cases

  • Database indexer: index transactions into external db
  • Monitoring, logging, reacting to events
  • Debugging, tracing

Implementation ideas / pseudocode

Go supports plugins. They can be built separately and injected at runtime.

There a working example for a feature that should be a plugin here: #13

config.toml

enableplugins = EsIndexerPlugin, FooBarPlugin

[EsIndexerPlugin]
pluginpath = ./path/to/aergoPluginEsIndexer.so
databaseurl = 127.0.0.1:9200
EsIndexerPlugin/plugin.go
package main

func init() {
  component = NewEsIndexer()
  hub := GetDefaultComponentHub()
  hub.Register(component)
  hub.Subscribe(event.NewBlock, component)
}


EsIndexerPlugin/EsIndexer.go
import (
	"github.com/aergoio/aergo/config"
	"github.com/aergoio/aergo/message"
	"github.com/aergoio/aergo/pkg/component"
	"github.com/aergoio/aergo/types"
)
type EsIndexer struct {
  conf *config.Config
  *component.BaseComponent
  hub *component.ComponentHub
}

EsIndexer.Receive
  switch msg := context.Message().(type) {
    case actor.Started:
      db = openDatabaseConnection(conf.EsIndexerPlugin.databaseurl)
      ...
      blockHeight = GetChainAccessor().GetBestBlock().GetHeader().GetBlockNo()
      ...

    case event.NewBlock:
      // sync new block
      db.index('block', msg.hash, msg.metadata)
      for tx in msg.txsList:
        db.index('tx', tx.hash, tx.metadata)
  }
@graup graup added feature New feature or request help wanted Extra attention is needed labels Nov 21, 2018
@graup
Copy link
Member Author

graup commented Nov 27, 2018

I started playing around with this idea, but it is actually not as easy as I thought. You cannot just import "github.com/aergoio/aergo/types" in a plugin, as that contains a bunch of dependencies, some of which (e.g. grpc -> net/trace) complain when multiple instance of them are loaded in a binary. The actor/component has a similar problem.

In order to make internal types available for other Go packages, the basic types should be usable in a more standalone way.

@graup
Copy link
Member Author

graup commented Nov 27, 2018

To complicate things further, sharing types between go packages that don't use the exact same sources doesn't work at all: golang/go#18827

This renders go plugins pretty much useless for my use case. We need to think of a different solution.

@graup
Copy link
Member Author

graup commented Nov 27, 2018

Maybe this approach can make sense: https://github.com/hashicorp/go-plugin
Basically run the plugin in a subprocess and communicate over grpc.

Especially since we're already using grpc.

@graup graup self-assigned this Nov 27, 2018
@graup graup added this to the Testnet milestone Nov 28, 2018
@graup graup added proposal and removed feature New feature or request labels Nov 28, 2018
@graup
Copy link
Member Author

graup commented Dec 11, 2018

We decided to not pursue this for now. For most cases discussed so far, a standalone program is almost as effective as a plugin. We may revisit this issue later.

@graup graup closed this as completed Dec 11, 2018
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment
Labels
help wanted Extra attention is needed proposal
Projects
None yet
Development

No branches or pull requests

1 participant