Skip to content

Conversation

@2403905
Copy link

@2403905 2403905 commented May 7, 2025

Added the reva HTTP/GRPC servers constructor w/o the watcher and the os signal handling to make it driven by the ocis runtime.

owncloud/ocis#11170

@2403905 2403905 force-pushed the issue-11170 branch 3 times, most recently from 968fe4e to 6855086 Compare May 12, 2025 21:05
@2403905 2403905 force-pushed the issue-11170 branch 2 times, most recently from 56aaa8f to b45b1cb Compare May 15, 2025 09:04
@2403905 2403905 requested a review from jvillafanez May 19, 2025 09:19
@jvillafanez
Copy link
Member

Some things I've noticed:

  • Logging a Fatal error and not returning immediately seems wrong. If the error is really fatal, there shouldn't be anything else for us to do, so either the error isn't fatal or there is a bug there.
  • For the "drivenserver.go" file, I think it's better to split it into multiple files. There is a constant switching between drivenHTTPServer and drivenGRPCServer that makes it annoying to go through the file.
  • We might skip the isEnabledHTTP and isEnabledGRPC checks. We can return a server instance (or nil) and an error instead, which is a common pattern. Then we can split the RunDrivenServerWithOptions into RunDrivenHTTPServerWithOptions and RunDrivenGRPCServerWithOptions so we can also return the corresponding instance with the error there.
    • To skip the isEnabledHTTP check, we can assume that oCIS will take care of it in some way because it's oCIS the one preparing the configuration, so it knows whether the HTTP or GRPC server will be needed and the required configuration should be there. As far as I know, reva only checks there is configuration for the service, but it doesn't check any value.

@2403905
Copy link
Author

2403905 commented May 21, 2025

Logging a Fatal error and not returning immediately seems wrong. If the error is really fatal, there shouldn't be anything else for us to do, so either the error isn't fatal or there is a bug there.

Changed: After logging Fatal and returning nil or err, no matter what exactly the ocis anyway must die. The os.Exit(1) was replaced by Fatal because the os.Exit(1) kills the ocis earlier than all log messages printed.

We might skip the isEnabledHTTP and isEnabledGRPC checks. We can return a server instance (or nil) and an error instead, which is a common pattern. Then we can split the RunDrivenServerWithOptions into RunDrivenHTTPServerWithOptions and RunDrivenGRPCServerWithOptions so we can also return the corresponding instance with the error there.
To skip the isEnabledHTTP check, we can assume that oCIS will take care of it in some way because it's oCIS the one preparing the configuration, so it knows whether the HTTP or GRPC server will be needed and the required configuration should be there. As far as I know, reva only checks there is configuration for the service, but it doesn't check any value.

The constructors return nil if no server is expected or die if misconfigured.

@2403905 2403905 requested a review from jvillafanez May 21, 2025 16:00
func (s *Server) Stop() error {
s.cleanupServices()
s.s.Stop()
s.cleanupServices()
Copy link
Author

Choose a reason for hiding this comment

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

@jvillafanez I assumed that we should stop the Listen first and then clean the services. Could you check if it makes sense?

Copy link
Member

Choose a reason for hiding this comment

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

As far as I know, this Stop method will be call by a secondary thread because the main one will be running the service. Once we call s.s.Stop(), the main thread will keep going, so there is a risk that the app finishes without having run the s.cleanupServices() (or maybe it runs partially for some services until the app closes).
Maybe I'm wrong, there are too many Stop methods and it's hard to know which one we're calling here.

@2403905 2403905 marked this pull request as ready for review May 21, 2025 16:21
@2403905 2403905 requested a review from kobergj May 21, 2025 16:21
Copy link
Collaborator

@kobergj kobergj left a comment

Choose a reason for hiding this comment

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

Just small question. Code looks good 👍

@2403905 2403905 requested a review from kobergj May 22, 2025 09:41
kobergj
kobergj previously approved these changes May 22, 2025
// NewDrivenHTTPServerWithOptions runs a revad server w/o watcher with the given config file and options.
// Use it in cases where you want to run a revad server without the need for a watcher and the os signal handling as a part of another runtime.
// Returns nil if no http server is configured in the config file.
// Throws a fatal error if the http server cannot be created.
Copy link
Member

Choose a reason for hiding this comment

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

Just saying that throwing isn't logging.

The code is fine if we consider that the fatal log won't happen in practice. If something is wrong, it should be fixed during development.

Copy link
Author

Choose a reason for hiding this comment

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

Just saying that throwing isn't logging.

Why? I can rephrase it, the meaning remains the same. Both log.Fatal() and options.Logger.Fatal() will print a message and then call an os.Exit(1).
I can change // Throws a fatal error if the http server cannot be created. to // Call a fatal error if the http server cannot be created.

The only way wrong is if we call the logger and then exit(1) because there is a very big chance that we never see this log.

			options.Logger.Error().Err(err).Msg("error runnig server")
			w.Exit(1)

Copy link
Member

Choose a reason for hiding this comment

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

It's just a wording change in the comment. Logs a fatal error seems more clear to me.
Throw is a keyword in other languages such as Java and PHP, and it have a very specific meaning. Even if we consider Go language, it might be confusing specially when the function doesn't return (or "throw") an error that we could handle upwards.
As said, the code is fine, it's just the wording.

Copy link
Author

Choose a reason for hiding this comment

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

ok. updated.

@2403905 2403905 requested a review from kobergj May 22, 2025 15:12
kobergj
kobergj previously approved these changes May 23, 2025
@jvillafanez
Copy link
Member

I assume we don't want to be too strict with the gracefulShutdownTimeout waiting time. I mean, we spawn a goroutine to stop and wait, but there is no guarantee that the goroutine will have enough time to run. There is a chance that the we reach the timeout but the goroutine didn't even start to run.
Of course, this scenario is too extreme, even more the longer the timeout is. I'm fine with the current code for the sake of simplicity, but maybe we should document somewhere that the timeout shouldn't be less then 5 secs (or whatever value is the standard in our case)

jvillafanez
jvillafanez previously approved these changes May 23, 2025
@2403905 2403905 dismissed stale reviews from jvillafanez and kobergj via 120ba81 May 26, 2025 06:53
// Use it in cases where you want to run a revad server without the need for a watcher and the os signal handling as a part of another runtime.
// Returns nil if no http server is configured in the config file.
// The GracefulShutdownTimeout set to default 20 seconds and can be overridden in the core config.
// Logging a fatal error and exit with code 1 if the http server cannot be created.
Copy link
Member

Choose a reason for hiding this comment

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

The "exit with code 1" is misleading because the function never does it. As it is written, it seems there is a os.Exit(-1) call hidden somewhere inside this function, but it isn't the case.

If, as a result of this function returning nil, the main app decides to exit with code 1, that's fine, but it's something this function doesn't need to care about. Whatever the caller does with the result of this function isn't this function's business.

@2403905
Copy link
Author

2403905 commented May 26, 2025

I assume we don't want to be too strict with the gracefulShutdownTimeout waiting time. I mean, we spawn a goroutine to stop and wait, but there is no guarantee that the goroutine will have enough time to run. There is a chance that the we reach the timeout but the goroutine didn't even start to run. Of course, this scenario is too extreme, even more the longer the timeout is. I'm fine with the current code for the sake of simplicity, but maybe we should document somewhere that the timeout shouldn't be less then 5 secs (or whatever value is the standard in our case)

Added the comments.

@2403905 2403905 merged commit 39d076b into owncloud:main May 26, 2025
1 check passed
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