-
Notifications
You must be signed in to change notification settings - Fork 2
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
Refactor Backfill #78
Conversation
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
If you dont close the channel, there is no way for other goroutine to know when to stop reading from that channel.
I suggest you create a channel inside the backfill function and return the read-only channel to the caller. This will give backfill function fully control over the channel preventing other goroutines from closing it.
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Why dont you make Backfill function non-blocking (start a goroutine inside the function); create the channel inside the function and return it the the caller?
When the caller creates a channel and pass it to a function, it is expected to take ownership over that channel so that the function shouldnt close that channel but leave it for the caller to control the life circle of that channel.
This is how the Backfill function should be used:
c, err := Backfill()
if err != nil {
return
}
for m := range c {
}
That is bad practice. It can cause memory leak.
Channel would close when function returns.
Sender function can close to signal there is nothing else to send. Otherwise how could you iterate over a channel? It is receiver function that shouldn't close. |
I dont believe it is a bad practice. This is an example of how a function should be designed in async-await model:
With this design, the caller doesnt need to create a channel nor start a goroutine by itself. It makes an async function act like a sync function from the caller's perspective, which is much simpler to use |
I thought you wanted to put the whole function inside a separate goroutine which is bad practice, such as:
This design will save the caller 1 line of code. So it is more of a convenience. Anyway, I implemented it for you. old:
new:
|
27cdae7
to
f87fa0d
Compare
f87fa0d
to
2c73dd3
Compare
Why dont you just modify Backfill and BackfillFrom instead of adding a new function? It is confusing for users having too many options to choose from. This will make Backfill and BackfillFrom deprecated btw |
You can't just modify Backfill and BackfillFrom as they work differently. I created new functions and deprecated these two. |
chain/ethereum/ethereum.go
Outdated
|
||
// HistoricalEvents queries past blocks for the events emitted by the given contract addresses. | ||
// These events are provided in a channel and ready to be consumed by the caller. | ||
func HistoricalEvents(ctx context.Context, client *ethclient.Client, addresses []common.Address, fromBlock uint64, toBlock uint64) chan types.Log { |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Can you return a read-only channel instead? Like this:
chan<- types.Log
chain/ethereum/ethereum.go
Outdated
// These events are provided in a channel and ready to be consumed by the caller. | ||
func HistoricalEvents(ctx context.Context, client *ethclient.Client, addresses []common.Address, fromBlock uint64, toBlock uint64) chan types.Log { | ||
if fromBlock == toBlock { | ||
return nil |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Return a nil channel can cause unexpexted result for caller who reads from this channel.
You can return a closed channel or return a nil channel with an error instead.
chain/ethereum/ethereum.go
Outdated
} | ||
|
||
if fromBlock >= toBlock { | ||
return nil |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Return a nil channel can cause unexpexted result for caller who reads from this channel.
You can return a closed channel or return a nil channel with an error instead
chain/ethereum/ethereum.go
Outdated
toBlock, err := client.BlockNumber(ctx) | ||
if err != nil { | ||
log.Error().Err(err).Msg("failed to get block number") | ||
return nil |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Return a nil channel can cause unexpexted result for caller who reads from this channel.
You can return a closed channel or return a nil channel with an error instead
chain/ethereum/ethereum.go
Outdated
} | ||
return HistoricalEvents(ctx, client, addresses, toBlock-numBlocks, toBlock) | ||
default: | ||
return nil |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Return a nil channel can cause unexpexted result for caller who reads from this channel.
You can return a closed channel or return a nil channel with an error instead
chain/ethereum/ethereum.go
Outdated
// * fromBlock > 0 && numBlocks > 0 => Backfill from fromBlock to fromBlock+numBlocks | ||
// * fromBlock > 0 && numBlocks = 0 => Backfill from fromBlock to current latest block | ||
// * fromBlock = 0 && numBlocks > 0 => Backfill last numBlocks blocks | ||
func HistoricalEventsWithQueryParams(ctx context.Context, client *ethclient.Client, addresses []common.Address, fromBlock uint64, numBlocks uint64) chan types.Log { |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Can you return a read-only channel instead? Like this:
chan<- types.Log
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
that's send-only but I changed them to receive-only <-chan ..
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Approved but here is some things you might want to change:
- If you already close the channel before returning it, you dont need to return an error anymore since it is fine reading from a closed channel.
- If you want to return an error, which I think is not necessary, then you can return a nil channel since returning an error already means you should not read from the channel.
So you can just remove the second return, which is the error, for convinient. Remember to log the error if you dont return them
Removes channel closing by sender to allow multithreading