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

PLT-7497: restructure Marconi with a focus on logging #212

Draft
wants to merge 4 commits into
base: main
Choose a base branch
from

Conversation

ana-pantilie
Copy link
Contributor

Pre-submit checklist:

  • Branch
    • Tests are provided (if possible)
    • Commit sequence broadly makes sense and have useful messages
    • Important changes are reflected in changelog.d of the affected packages
    • Relevant tickets are mentioned in commit messages
  • PR
    • (For external contributions) Corresponding issue exists and is linked in the description
    • Targeting main unless this is a cherry-pick backport
    • Self-reviewed the diff
    • Useful pull request description
    • If relevant, reference the ADR in the PR and reference the PR in the ADR
    • Reviewer requested

Copy link
Contributor

@neilmayhew neilmayhew left a comment

Choose a reason for hiding this comment

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

My comments and suggestions here are fairly random and untested, so feel free to ignore them if they don't seem like they will work

marconi-chain-index/src/Marconi/ChainIndex/Logging.hs Outdated Show resolved Hide resolved
Comment on lines 67 to 68
-- TODO: this should also throw an exception
logMError = undefined
Copy link
Contributor

Choose a reason for hiding this comment

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

I feel like log functions shouldn't be throwing exceptions, despite what we said earlier today about having a unified framework for both.

Perhaps it would be OK to have a function that does both, but have that reflected in the name. Something like logThrowError.

In another system I worked on, we also included a "context" parameter which was just a string that indicated where the error was thrown from. This helped a lot when looking at logs.

Copy link
Contributor Author

Choose a reason for hiding this comment

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

I agree, I think we need to have the concrete requirements regarding errors and exceptions in order to make any changes here.

Comment on lines 36 to 38
-- TODO: this function is problematic because it is used both inside the
-- ChainIndexT context and outside to initialize the config
-- see Marconi.ChainIndex.Run.run
Copy link
Contributor

Choose a reason for hiding this comment

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

Could you make the monad be a type parameter m and give it constraints (MonadIO m, MonadUnliftIO m)?

Or have two versions of the function, one of which wraps the other and lives in ChainIndexT?

Copy link
Contributor Author

Choose a reason for hiding this comment

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

I'm not sure about using MonadUnliftIO. If I understand correctly, it looks like we'd be restricting our ChainIndexT monad stack to just having reader capabilites, and I don't have enough knowledge about the domain if we need to worry about this or not.

Copy link
Contributor Author

Choose a reason for hiding this comment

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

Hmm, still, for the second solution I believe you end up explicitly implementing the ChainIndexT -> IO transformation. Unfortunately this isn't the only place in the code this transformation is needed I think, not 100% sure yet but wanted to add to my previous comment.

marconi-chain-index/src/Marconi/ChainIndex/Types.hs Outdated Show resolved Hide resolved
Copy link
Contributor

@neilmayhew neilmayhew left a comment

Choose a reason for hiding this comment

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

This is coming together nicely

Comment on lines +684 to +699
liftIO
. Utils.toException
$ Utils.queryCurrentNodeBlockNo @Void networkId socketPath
let indexers = mapMaybe sequenceA indexerList
coordinator <- liftIO $ initializeCoordinatorFromIndexers securityParam indexingDepth indexers
let indexerDepth =
let SecurityParam s = securityParam
in case indexingDepth of
MinIndexingDepth d -> SecurityParam $ s - d + 1
MaxIndexingDepth -> SecurityParam 1
resumablePoints <-
liftIO $ getStartingPointsFromIndexers indexerDepth currentNodeBlockNo indexers coordinator
let oldestCommonChainPoint = minimum resumablePoints
resumePoint = case cliChainPoint of
C.ChainPointAtGenesis -> oldestCommonChainPoint -- User didn't specify a chain point, use oldest common chain point,
cliCp -> cliCp -- otherwise use what was provided on CLI.
Copy link
Contributor

@neilmayhew neilmayhew Oct 25, 2023

Choose a reason for hiding this comment

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

I think you could avoid some of the uses of liftIO by moving these lines outside of withNodeConnectRetryMarconi. I don't think any of them have to run in ChainIndexerT.

However, maybe you plan to migrate more of these functions to ChainIndexerT eventually, so they can get their parameters from the reader env. In which case, they would need to stay where they are.

mkIndexerStream coordinator
. chainSyncEventStreamLogging
. updateProcessedBlocksMetric
runChainSyncStream = liftIO $ withChainSyncBlockEventStream socketPath networkId [resumePoint] stream
Copy link
Contributor

Choose a reason for hiding this comment

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

Now that withChainSyncBlockEventStream runs in MonadIO I don't think you need a liftIO here.

Copy link
Contributor Author

Choose a reason for hiding this comment

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

Overview of one of the problems encountered in my investigation

chainSyncEventStreamLogging needs to have access to the logging context.

The stream is problematic here because it needs to both be in the ChainIndexT context (as noted above) and in IO because it is run by withChainSyncBlockEventStream. Inside, it uses withAsync on the stream consumer which means that we would need a way to "unlift" the ChainIndexT back to IO.

This brings forward the question of whether we can make ChainIndexT an instance of MonadUnliftIO. This would restrict the monad stack to allow only the current reader capability, and also it does not play well with the ExceptT we have decided to keep (as per @willjgould's investigation).

I believe that there are two possible ways to go on from here:

  1. we make ChainIndexT an instance of MonadUnliftIO and see how it impacts the usage of ExceptT, keeping in mind the restrictions we will impose
  2. we refactor the code in such a way that rids it of how deeply coupled it is with IO now, as Will also suggested; I don't know if this is possible, someone with more knowledge of the business logic should have a better idea than me

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.

2 participants