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

application startup should fail if initial download of a single list failed (#310) #313

Merged
merged 17 commits into from
Oct 13, 2021

Conversation

kwitsch
Copy link
Collaborator

@kwitsch kwitsch commented Oct 10, 2021

Changes:

  • server.go:NewServer -> returns multpiple errors instead of one
  • Resolver interface -> new function GetInitErrors returns slice of errors which occured during resolver initialisation
  • list_cache.go:NewListCache -> additionaly returns slice of errors which occured during resolver initialisation
  • list_cache.go -> modified error handling

@kwitsch
Copy link
Collaborator Author

kwitsch commented Oct 11, 2021

Sorry I'm fairly new to unit tests, will try fixing the problem.

@0xERR0R
Copy link
Owner

0xERR0R commented Oct 11, 2021

Hi, thank you for your work!
I'll review your PR in detail today or tomorrow. After a short look, I have one question:
You introduced new function in the interface "Resolver": GetInitErrors() []error
Since this function is in the most cases empty (in makes only sense for BlockingResolver), would it not be better to remove this function and return all initialization errors in correspondent "New...Resolver" methods (e.g. NewBlockingResolver)? I think it would be more cleaner, but maybe there is a reason for it...

@kwitsch
Copy link
Collaborator Author

kwitsch commented Oct 11, 2021

Hi, thank you for your work! I'll review your PR in detail today or tomorrow. After a short look, I have one question: You introduced new function in the interface "Resolver": GetInitErrors() []error Since this function is in the most cases empty (in makes only sense for BlockingResolver), would it not be better to remove this function and return all initialization errors in correspondent "New...Resolver" methods (e.g. NewBlockingResolver)? I think it would be more cleaner, but maybe there is a reason for it...

Hi, I added the functions as stub for further error handling.
The upstream_resolver and the parallel_best_resolver could also return errors which are, as far as i know, not currently handeld(upstream resolver is not an IP and cant't be resolved).

I tried to introduce a generic solution for error handling during server startup but I'm still kind of new to the conzept of working without methode overrides and abstract classes so there will be a better solution for sure(got stuck at the Chain function). 😅

@0xERR0R
Copy link
Owner

0xERR0R commented Oct 11, 2021

Its a good idea to prepare the code to handle errors in all resolvers. I think the errors could be handled just before the chain func. following must be replaced

return resolver.Chain(
		resolver.NewIPv6Checker(cfg.DisableIPv6),
		resolver.NewClientNamesResolver(cfg.ClientLookup),
		resolver.NewQueryLoggingResolver(cfg.QueryLog),
		resolver.NewMetricsResolver(cfg.Prometheus),
		resolver.NewCustomDNSResolver(cfg.CustomDNS),
		resolver.NewBlockingResolver(cfg.Blocking),
		resolver.NewCachingResolver(cfg.Caching),
		resolver.NewConditionalUpstreamResolver(cfg.Conditional),
		resolver.NewParallelBestResolver(cfg.Upstream.ExternalResolvers),
	)

by invoking each "New*" function and collecting errors. In error case -> log errors and fail to start, if no error occurred -> call chain function.

for group, links := range b.groupToLinks {
cacheForGroup := b.createCacheForGroup(links)

Copy link
Owner

Choose a reason for hiding this comment

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

The logic based on "elementCount" doesn't work if a group has multiple links and some of them are successful, for Example this config:

port: 55555
logLevel: info

blocking:
  blackLists:
    xyz:
      - /wrongpath/whitelist.txt
    ads:
      - http://wrongdomain/hosts.txt
      - https://s3.amazonaws.com/lists.disconnect.me/simple_tracking.txt
upstream:
  default:
    - https://8.8.8.8/dns-query
    - https://8.8.4.4/dns-query

I would expect 2 errors, but I get only one, because the "ads" group has more than 0 elements

Copy link
Collaborator Author

Choose a reason for hiding this comment

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

I tested this scenario with commit b41ccc3 but as the unit test(list_cache_test.go:133) indicated that this was the expected behavior. The commit was reverted afterwards in commit 98ddbb2.
I missed to test the following solution throughout. 😞

I would propose to let createCacheForGroup additionally return errors, which could be handeld afterwards.

@@ -205,22 219,27 @@ func (b *ListCache) downloadFile(link string) (io.ReadCloser, error) {
if resp, err = client.Get(link); err == nil {
if resp.StatusCode == http.StatusOK {
return resp.Body, nil
} else {
Copy link
Owner

Choose a reason for hiding this comment

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

👍

@0xERR0R
Copy link
Owner

0xERR0R commented Oct 11, 2021

Hey,
I could take a look on your PR, I understand the idea and your changes in error handling are great. I added some comments, please let us discuss it. I'm open for ideas and I think we are on the good way.

@kwitsch
Copy link
Collaborator Author

kwitsch commented Oct 12, 2021

Hey, I could take a look on your PR, I understand the idea and your changes in error handling are great. I added some comments, please let us discuss it. I'm open for ideas and I think we are on the good way.

Hi, already seen it and answered 😉
I try coming up with a better solution.
For a more unittested solution I need to learn working with unittests in golang first...sorry for the inconvenience 😕

@0xERR0R
Copy link
Owner

0xERR0R commented Oct 12, 2021

Let me know if you need help or if I can take a task or a part

@kwitsch
Copy link
Collaborator Author

kwitsch commented Oct 12, 2021

I tested this solution with your config which results in two errors and 'make test' got through without errors.
No unit test for this scenario jet.

attempt
} else {
return nil, err
} else if errors.As(err, &dnsErr) {
Copy link
Owner

Choose a reason for hiding this comment

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

Different message for DNS resolution errors 👍

@@ -47,7 47,7 @@ func getServerAddress(addr string) string {
}

// NewServer creates new server instance with passed config
func NewServer(cfg *config.Config) (server *Server, err error) {
func NewServer(cfg *config.Config) (server *Server, errors []error) {
Copy link
Owner

@0xERR0R 0xERR0R Oct 11, 2021

Choose a reason for hiding this comment

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

Discussion: typically in Go, if a function can't handle error internally, it returns an error as the last parameter. It is possible to combine multiple errors into one with wrapping (see error wrapping). Here is some example: https://play.golang.org/p/Kwbek7RV1Lw

I think it would be more "go-ish" to return here just "error" and not a slice of errors. If multiple errors can ocurre, they should be wrapped. This would make the code simpler and convenient.

What do you think?

We can also merge it with error slice, I'm currently not sure what is the better solution

Copy link
Collaborator Author

Choose a reason for hiding this comment

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

Didn't know about the wrapping and seen error more than some kind of object than an actual exception 😅
Wrapping them seems logical.

@codecov
Copy link

codecov bot commented Oct 12, 2021

Codecov Report

Merging #313 (84bd924) into development (c22292e) will decrease coverage by 0.63%.
The diff coverage is 81.44%.

Impacted file tree graph

@@               Coverage Diff               @@
##           development     #313       /-   ##
===============================================
- Coverage        95.27%   94.64%   -0.64%     
===============================================
  Files               29       29              
  Lines             2160     2202       42     
===============================================
  Hits              2058     2084       26     
- Misses              74       83        9     
- Partials            28       35        7     
Impacted Files Coverage Δ
resolver/blocking_resolver.go 98.31% <55.55%> (-1.69%) ⬇️
util/common.go 94.06% <61.53%> (-4.09%) ⬇️
server/server.go 79.38% <79.16%> (-1.05%) ⬇️
lists/list_cache.go 94.28% <92.00%> (-1.80%) ⬇️
cmd/serve.go 100.00% <100.00%> (ø)

Continue to review full report at Codecov.

Legend - Click here to learn more
Δ = absolute <relative> (impact), ø = not affected, ? = missing data
Powered by Codecov. Last update c22292e...84bd924. Read the comment docs.

@0xERR0R 0xERR0R changed the title Fix for ticket #285 by implementing ticket #310 application startup should fail if initial download of a single list failed (#310) Oct 12, 2021
@0xERR0R 0xERR0R merged commit e5b44f4 into 0xERR0R:development Oct 13, 2021
@0xERR0R 0xERR0R linked an issue Nov 14, 2021 that may be closed by this pull request
@kwitsch kwitsch deleted the #285#310 branch November 15, 2021 10:29
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.

v0.16 crashes at startup if no blacklists are available
2 participants