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

More backends refactoring #71

Merged
merged 60 commits into from
Mar 21, 2017
Merged

More backends refactoring #71

merged 60 commits into from
Mar 21, 2017

Conversation

flashmob
Copy link
Owner

@flashmob flashmob commented Feb 10, 2017

Edit: deleted comment as no longer relevant! See new comment

- Hasher decorator
- MySQL decorator

also fixes a bug with header parsing

Todo:
redis decorator, cleanup / remove legacy code, finalise interfaces
- Compressor decorator
- Header decorator
- Redis decorator

Other:
Moved events to its own package so that they can be used by backend without getting into circular dep.
Guerrilla embeds events directly instead of wrapping the function

Todo:
, cleanup / remove legacy code, finalise interfaces, change processor initialize to use events. Use a channel for backend errors.
- processor lines can configured via config and built during initialization
- backend gateway manages creating of processor lines and starting / stopping workers that use these lines
- TODO: lots of cleanup, change to allow multiple rcpt to, more comments, test backend shutdown/restart on config reload
@flashmob
Copy link
Owner Author

flashmob commented Feb 14, 2017

This is a huge... YYYYYUGE... backend refactor!

The main idea is to break backend processing down to individual, reusable components. In a nutshell, you'll now be able to customize your backend by configuration, like so:

"process_line": "HeadersParser|Debugger|Hasher|Header|Compressor|Redis|MySql"

Tokens are separated by a pipe '|'. Each token is a component called a "Processor". When an email is processed, it goes through each component in a line, starting at the left and ending on the right.

How's this implemented?
It's using a decorator pattern found here https://github.com/smaxwellstewart/golang-decorator-pattern
The video was mind-blowing https://www.youtube.com/watch?v=xyDkyFjzFVc

Still need to finalize some things, clean up and determine which interfaces / values need to be public.

- add comments at the start of all processors
- Remove initializers / shutdowners once backend is shutdown
- redis processor: propagate close error
- mysql processor: propaget close error
- add more comments
- Added in type support to Backend's extractConfig func
- saveStatus contains queued instead of hash, better semantically
- BackendGateway default config if processor_line not present, or save_workers_size not present
- added queued id to envelope, a temporary default id is generated too
…reation

- Made some symbols public, ie. Service.ExtractConfig, BaseConfig
- Envelope: added a NewRreader() function that returns a reader for the processed email
- Moved resetting the envelope from client.go to envelope itself.
- Added a Reseed() function that seeds the envelope with data at the start of a connection
- rename Service to Svc
- rename BackendResult to Result (the package already has the word backend)
- rename saveStatus to notifyMsg to better reflect what it does
-Rename NewBackendResult to NewResult
- add ValidateRcpt method to Backend interface
- use private vars where possible
- Added the Errors type
- Svc.shutdown returns Errors
- Svc.initialize returns Errors
- renamed savePayload to workerMsg for a more general name
- added a new validateRcptChan channel
- savedNotify renamed to  notifyMe for more fluent code readability
- backend timeout now a constant  ProcessTimeout
- new ValidateRcpt method implimented to add validateRcptChan channel
- getNumberOfWorkers() renamed to workersSize()
- saveMailWorker() renamed to workDispatcher() so the name better reflects what it does
- Change the Processor interface to add a new task param, allows the selecting of what task to do (so far, save or validate)
- Update all processors to use new Processor interface
- Renamed Envelope.Info to Envelope.Values
- New Canned.FailRcptCmd response message for when recipient does not exist
- Added PushRcpt and PopRcpt to Envelope
…make sense. *email.Envelope reads better

- renamed saveMailChan to conveyor to be more concise
- merged validateRcptChan to conveyor - simplified
- ProcessorLine renamed ProcessorStack to better describe structure
- Default processor now a constant, used when no processor set in config
- Renamed Shutdown and Initialize types used for helping to pass closures that meet Shutdowner/Initializer interfaces, improves readability
 - config extractor now supports omitempty json struct tag
 - server now checks RCPTO using backend gateway
-  rename RemoteAddress to RemoteIP for clarity (form a module point of view, it now looks like mail.Address{} instead of envelope.EmailAddress{})
- updated the sample config
- backend_name removed from config
- test mysql connection & access to table
- guerrilla-redis-db processor bug fix
- rename constants for the mysql processor
- update readme
- remove name from nackends.New
- Update readme to reflect code
- make test
Copy link
Collaborator

Choose a reason for hiding this comment

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

👍

api.go Outdated
"time"
)

type Daemon struct {
Copy link
Collaborator

Choose a reason for hiding this comment

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

Could add a comment here about how Daemon differs from the Guerrilla struct

Copy link
Owner Author

Choose a reason for hiding this comment

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

👍

api.go Outdated
return errors.New("d.Config nil")
}
var oldConfig AppConfig
oldConfig = *d.Config
Copy link
Collaborator

Choose a reason for hiding this comment

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

can merge lines 130-131

api.go Outdated
if err == nil {
l.SetLevel("info")
}
return l
Copy link
Collaborator

Choose a reason for hiding this comment

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

This should probably do some error checking or return an error. Looks like if an error is returned on line 174 this will return nil and caller will panic. Although this is probably used to frequently for error checking on the caller to be reasonable. Maybe cache a log in the daemon/guerrilla struct when logs are rotated/changed and get that directly afterward. Error check on getting log when rotating, afterward isn't required.

return NewResult(response.Canned.FailBackendNotRunning + gw.State.String())
}
// place on the channel so that one of the save mail workers can pick it up
savedNotify := make(chan *notifyMsg)
Copy link
Collaborator

Choose a reason for hiding this comment

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

Considering how frequently we're calling Process and ValidateRcpt, these notifyMsg channels might be a good candidate for pooling

sc.Hostname = h
sc.MaxClients = 100
sc.Timeout = 30
sc.MaxSize = 10 << 20 // 10 Mebibytes
Copy link
Collaborator

Choose a reason for hiding this comment

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

typo: Megabytes

c.Servers[i].Timeout = 20
}
if c.Servers[i].MaxSize == 0 {
c.Servers[i].MaxSize = 10 << 20 // 10 Mebibytes
Copy link
Collaborator

Choose a reason for hiding this comment

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

typo: megabytes

guerrilla.go Outdated
}
return nil
}

func (g *guerrilla) Shutdown() {

// shot down the servers first
Copy link
Collaborator

Choose a reason for hiding this comment

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

typo: shut down

mail/envelope.go Outdated
"time"
)

const maxHeaderChunk = iota + (3 << 10) // 3KB
Copy link
Collaborator

Choose a reason for hiding this comment

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

Why use iota here instead of just 1?

server.go Outdated
@@ -136,6 +137,19 @@ func (s *server) configureLog() {
}
}

// setBackend Sets the backend to use for processing email envelopes
Copy link
Collaborator

Choose a reason for hiding this comment

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

sets

@flashmob
Copy link
Owner Author

Thanks @jordanschalm for the review - will be going through these today.

@flashmob
Copy link
Owner Author

@jordanschalm still going through it (and fixing problems), marking the ones that are fixed. Just want to say thanks again. Your reviews are very thorough with lots of attention to detail! Will have the new README ready for review soon too.

@flashmob
Copy link
Owner Author

Worked on adding the pooling of notifyMsg chans. Now working on another optimization: In ValidateRcpt, don't need to place on the channel if we know that there were no validators set in the config.

…tors configured

- fix issues found during code review on PR #71
- fix bug with server ignoring the -v flag
- default config now named as 'goguerrilla.conf.json' for syntax highlighting
- changed api so AppConfig is passed by value, so the caller can't modify it / prevent using it as global state value
- Safeguard api functions from calling out of order (check for nil)
- removed CmdConfig
@flashmob
Copy link
Owner Author

@jordanschalm Here is the new README ready for review - https://github.com/flashmob/go-guerrilla/blob/more-backends-refactoring/README.md - things to check: typos, grammar & flow. Also feedback on if it's using the right words to describe things. Thanks!

- fix race condition with the client pool
Copy link
Collaborator

@jordanschalm jordanschalm left a comment

Choose a reason for hiding this comment

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

This looks good to me. The README was getting pretty long, and I think this makes it a lot easier to get into. Ordering of topics is good. Intro->Features->Standalone->Package->Backend/Processors. Maybe could move the Starting/Usage and Using NGINX as a Proxy to where you first introduce the daemon in Getting Started as subsections or relegate them to the wiki. Besides that noticed a couple of typos.

README.md Outdated
====================

An minimalist SMTP server written in Go, made for receiving large volumes of mail.
An lightweight & modern SMTP server written in Go, made for receiving large volumes of mail.
Copy link
Collaborator

Choose a reason for hiding this comment

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

A lightweight

README.md Outdated
### What is Go Guerrilla SMTPd?
### What is Go-Guerrilla?

It's an SMTP written in Go, for the purpose of receiving large volume of email.
Copy link
Collaborator

Choose a reason for hiding this comment

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

an SMTP server

README.md Outdated
add_header Auth-Server 127.0.0.1;
add_header Auth-Port 2525;
}
The main job of a go-guerrilla backend is to validate recipients and deliver emails. The term
Copy link
Collaborator

Choose a reason for hiding this comment

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

Depending on how pedantic you want to be, could standardize the capitalization of "Go-Guerrilla". The README has Go-guerrilla, Go-Guerrilla, and go-guerrilla ;-)

README.md Outdated
### What is Go Guerrilla SMTPd?
### What is Go-Guerrilla?

It's an SMTP written in Go, for the purpose of receiving large volume of email.
Copy link
Collaborator

Choose a reason for hiding this comment

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

"receiving large volumes" or "receiving a large volume"

@flashmob
Copy link
Owner Author

@dvcrn @peterkrejci @mrcpvn @eliezedeck
Doing some final testing on this PR.
If all good - to be merged to master today!

@dvcrn
Copy link
Contributor

dvcrn commented Mar 21, 2017

@flashmob amazing 😄 fantastic job!

@flashmob flashmob merged commit 14a83f6 into master Mar 21, 2017
@flashmob flashmob deleted the more-backends-refactoring branch March 21, 2017 06:39
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment
Labels
None yet
Projects
None yet
Development

Successfully merging this pull request may close these issues.

3 participants