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

Add cats-effect to the core module, remove modes #345

Merged
merged 21 commits into from
Jul 31, 2020

Conversation

kubukoz
Copy link
Collaborator

@kubukoz kubukoz commented Feb 7, 2020

No description provided.

@kubukoz kubukoz mentioned this pull request Feb 7, 2020
@lewisjkl
Copy link
Collaborator

lewisjkl commented Feb 7, 2020

@kubukoz this is looking great! Feels so much cleaner without the modes 😅.

@cb372
Copy link
Owner

cb372 commented Feb 7, 2020

Great! The number of deleted lines is a good sign :) I’m on my phone now but I can take a proper look this weekend.

@kubukoz
Copy link
Collaborator Author

kubukoz commented Feb 7, 2020

@cb372 please do, if it looks good I'll proceed to migrate remaining modules.

Copy link
Owner

@cb372 cb372 left a comment

Choose a reason for hiding this comment

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

Looks great so far. Please continue 😄

else
Some(entry.value)
def doGet(key: String): F[Option[V]] = {
F.delay {
Copy link
Owner

Choose a reason for hiding this comment

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

nit: let's write one-liners like this as F.delay(...) instead of with curly braces.

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 have a personal preference of putting by-name parameters in curly braces (if the parameter list only has one parameter), especially when lifting side effects. But I can adjust :)

@@ -49,123 +55,92 @@ trait AbstractCache[V] extends Cache[V] with LoggingSupport {
if (logger.isDebugEnabled) {
logger.debug(s"Skipping cache PUT because cache writes are disabled. Key: $key")
}
mode.M.pure(())
F.pure(())
Copy link
Owner

Choose a reason for hiding this comment

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

F.unit ?

Copy link
Collaborator Author

Choose a reason for hiding this comment

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

That'll need .widen - F is invariant and we need F[Any] unless I change the interface's type. Which I want to do, but maybe as a different change.

*/
def close[F[_]]()(implicit mode: Mode[F]): F[Any]
//TODO: Replace with Resource-based API?
Copy link
Owner

Choose a reason for hiding this comment

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

Possibly, but let's save that for another PR

Copy link
Collaborator Author

Choose a reason for hiding this comment

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

sure

@lewisjkl
Copy link
Collaborator

if it looks good I'll proceed to migrate remaining modules.

I know we talked in #336 about potentially removing some of the cache implementations. Could be worth drawing a box around which ones we'd want to remove (if any) prior to doing the work of actually migrating them. If so, I can open another issue so we can come to a decision about which ones to potentially remove.

@kubukoz
Copy link
Collaborator Author

kubukoz commented Feb 13, 2020

@lewisjkl I'm totally on board with that, no point migrating code that is going to disappear. If you have some thoughts on which ones we'll remove, please bootstrap an issue :)

@lewisjkl lewisjkl linked an issue Feb 17, 2020 that may be closed by this pull request
@lewisjkl
Copy link
Collaborator

@kubukoz I just created #353 to discuss which cache implementations should be removed.

Sent with GitHawk

@cb372
Copy link
Owner

cb372 commented Feb 25, 2020

Hey @kubukoz thanks for waiting. We've now removed a few modules, so feel free to rebase and pick this work up again when you have time.

@kubukoz
Copy link
Collaborator Author

kubukoz commented Mar 15, 2020

Hey, I'll try to get back to this soon. Finished some other work so my bandwidth is a bit wider now...

@kubukoz
Copy link
Collaborator Author

kubukoz commented Mar 22, 2020

@cb372 @lewisjkl how do you feel about logging? Currently we have impure logging all over the place, and it should be suspended.

I see the following options as best:

  • keep the current logging but lift it manually via Sync
  • depend on log4cats (it'll increase the amount of work to start using scalacache, as users will need to create a logger themselves)

For convenience, I'd go with the first, but not everyone will want to use slf4j (as we do now), which might be a problem later. What do you think?

@lewisjkl
Copy link
Collaborator

depend on log4cats (it'll increase the amount of work to start using scalacache, as users will need to create a logger themselves)

This would be great if not for requiring that extra setup. Do you think there’d be any good way to set a default to a no-op logger that is overridable if a user desires? If so, is that something worth doing?

Otherwise the sync option could be safer for now until we can think of a way to lower the friction to integrate and provide logging decoupled from a logging backend. I can definitely be persuaded here though.

@kubukoz
Copy link
Collaborator Author

kubukoz commented Mar 23, 2020

I think it's a reasonable course of action to proceed without anything smarter than Sync for now. Before the big bang release we can think about having it configurable. A no-op default certainly sounds possible in a way that makes it easy to override, as people don't create new caches all around the place (so less risk of inconsistent instances across the codebase).

@lewisjkl
Copy link
Collaborator

@kubukoz is there anything that I can do to help push this along? I'm not trying to push you to do anything here, just know that I am happy to help if you don't currently have the bandwidth 😄

@kubukoz
Copy link
Collaborator Author

kubukoz commented May 27, 2020

@kubukoz is there anything that I can do to help push this along? I'm not trying to push you to do anything here, just know that I am happy to help if you don't currently have the bandwidth 😄

I'd love to finally do this, as it's been open for a while... I'll get back to it so I'm not blocking further improvements any longer.

@cb372
Copy link
Owner

cb372 commented May 28, 2020

Yeah it would be great to get this one over the line 😄 Let me know if I can help.

By traversing on the entry's TTL we get the opportunity to avoid
calculating the time in case there's no TTL. That might give us some
extra performance in case of infinitely long-lived keys.

The constraint is more powerful, but all the caching implementations
will be at least monads, so it's fine. And Clock is only possible to
implement in a real scenario for instances of Sync.
@kubukoz
Copy link
Collaborator Author

kubukoz commented May 31, 2020

Apparently the redis cluster tests aren't working yet, and I haven't been able to set it up locally yet... I'll see what I can do.

Comment on lines +27 to +30
.map {
case None | Some(true) => true
case Some(false) => false
}
Copy link
Collaborator

Choose a reason for hiding this comment

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

What about .forall(identity)?
Maybe that would just be harder to read, but thought I'd throw it out there.

Copy link
Collaborator Author

Choose a reason for hiding this comment

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

Yeah, I had that but decided an explicit match would be more readable (in fact, I had a bug here due to having used contains / exists).

Copy link
Collaborator

Choose a reason for hiding this comment

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

Cool, yeah I agree that the match is more readable. You don't have to do the mental gymnastics of remembering forall defaults to true.

@lewisjkl
Copy link
Collaborator

lewisjkl commented Jun 1, 2020

@kubukoz thanks for going through all all of that! Just looked through and didn't see any missed delays or *>. I'd be happy to take a look at the redis tests as well, but I don't want to step on your toes either. Just lmk if I can help 🙂

@kubukoz
Copy link
Collaborator Author

kubukoz commented Jun 1, 2020

@kubukoz thanks for going through all all of that! Just looked through and didn't see any missed delays or *>. I'd be happy to take a look at the redis tests as well, but I don't want to step on your toes either. Just lmk if I can help 🙂

I'll give it one more attempt today and let you know how it went :)

@@ -1,23 +1,26 @@
package scalacache.logging

import org.slf4j.{Logger => Slf4jLogger, LoggerFactory}
import cats.effect.Sync
import cats.Applicative
import cats.implicits._

Choose a reason for hiding this comment

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

You don't appear to need this, based on what you are using I'd suggested targeted syntax:

import cats.syntax.option._
import cats.syntax.flatMap._

@@ -3,6 +3,11 @@ package scalacache
import scala.concurrent.duration.Duration

import scala.language.higherKinds
import cats.Monad
import cats.implicits._

Choose a reason for hiding this comment

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

targeted syntax for functor, monadError and flatMap

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'm not sure if there is a global standard for whether we want to use fine-grained imports or the whole thing. I can switch to either, but is there any improvement in using the targeted ones? The compilation time is roughly the same, from what I saw last time I checked.

Copy link
Owner

Choose a reason for hiding this comment

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

I try to use targeted imports as much as possible. Partially for compilation speed, although that is only anecdotal and wouldn't matter anyway on a project of this size. But more importantly for readability, as it gives readers more of a clue where instances and extension methods are coming from.

f: => F[V]
)(implicit mode: Mode[F], flags: Flags): F[V]
def cachingForMemoizeF(baseKey: String)(ttl: Option[Duration])(
f: F[V]

Choose a reason for hiding this comment

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

Call by name might still be useful here, since I don't think there is a restriction against using Future or Try is there?

Copy link
Collaborator Author

@kubukoz kubukoz Jun 19, 2020

Choose a reason for hiding this comment

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

Neither Future nor Try have cats-effect instances, which you need anyway (Sync, for some impls. Async).

@cb372
Copy link
Owner

cb372 commented Jun 27, 2020

Sorry everyone, I should have been pushing this PR a bit harder but I keep getting distracted.

@lewisjkl do you want to pick it up and try to get the tests working so we can get it merged and start working towards a release?

@kubukoz Thank you for all your work so far!

@lewisjkl
Copy link
Collaborator

@lewisjkl do you want to pick it up and try to get the tests working so we can get it merged and start working towards a release?

I would be happy to pick this up. I’ll take a look within the next couple of days and see if I can get those tests passing.

@lewisjkl
Copy link
Collaborator

Started to look at the tests this morning. So far I tried to get a local redis cluster set up using docker-compose. I am able to get the tests in the integrationtests package to pass just fine, but the ones in RedisClusterCacheSpec are just hanging when I run them. I noticed that there is a make file in the project for setting up with Travis, but I am on a Mac rather than Linux so it didn't seem completely well suited for me. How do you typically go about running these locally @cb372? I am thinking I will keep going with the docker stuff I have up unless you have a better or more proven way.

@cb372
Copy link
Owner

cb372 commented Jul 2, 2020

@lewisjkl I don't think I've ever run the cluster tests locally. Somebody else contributed that makefile and I've always relied on Travis to run those test for me.

In the past I installed redis via brew and fiddled around with config files to get Redis Sentinel working, but never tried for cluster. Docker sounds like a better idea.

@lewisjkl
Copy link
Collaborator

lewisjkl commented Jul 2, 2020

@cb372 sounds good, thanks for the info. Mostly just wanted to make sure I wasn't reinventing the wheel here. I will see what I can get figured out with Docker. If I come up with something noteworthy then I will add it in a PR sometime soon.

@lewisjkl
Copy link
Collaborator

lewisjkl commented Jul 3, 2020

So now all of the tests are passing and the docs are compiling. With the docs, I do think that we should go through and reformat some of the sections. Just to get them compiling, I added things like .unsafeRunSync when it is probably not preferable, but it will be a slightly larger rewrite to get them working using .flatMap/regions of sharing. Do you think I should take the time to do that on this PR? Or should we split that out so we can get this one merged?

I also noticed that there was a todo or two in the changeset for this PR. I will track them down and open individual comments about them in this thread so we can ensure they are addressed.

@@ -3,19 +3,20 @@ package scalacache
import scala.concurrent.duration.Duration
import scala.language.higherKinds

trait Cache[V] extends CacheAlg[V] {
//todo merge with alg?
Copy link
Collaborator

Choose a reason for hiding this comment

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

Is this something we want to address in this PR? Seems like a good candidate for another PR to me, but happy to hear other opinions.

Copy link
Owner

Choose a reason for hiding this comment

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

Yes let's do this in another PR if we decide it's a good idea. I don't really remember why I separated Cache and CacheAlg in the first place.

@@ -7,74 +7,64 @@ import scala.language.higherKinds
/**
* Abstract algebra describing the operations a cache can perform
*
* @tparam F the effect of the cache. //todo elaborate
Copy link
Collaborator

Choose a reason for hiding this comment

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

I don't know how much elaboration is needed here. I think going too much more into depth on what F[_] means could be out of scope here.

Copy link
Owner

Choose a reason for hiding this comment

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

Yeah I think we can just remove the @tparam line completely. We'll assume that anyone using the library is familiar with tagless-final.

@@ -3,6 +3,7 @@ import scala.language.higherKinds

package object scalacache {

//todo
Copy link
Collaborator

Choose a reason for hiding this comment

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

Is this todo indicating that type Id[X] = X is able to be removed? I am guessing that it can be removed in favor of people using cats Id when appropriate. Although it won't be usable for any of the algebras requiring Sync/Async anyway..

Copy link
Owner

Choose a reason for hiding this comment

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

Yes I think this can be removed. I'll add a commit to do that.

@lewisjkl
Copy link
Collaborator

lewisjkl commented Jul 3, 2020

Also, for anyone curious, I ended up just using this repo (I also removed the password that is set by default in this repo) to test with Redis locally.

@cb372 cb372 marked this pull request as ready for review July 31, 2020 15:35
@cb372 cb372 merged commit 7fdf424 into cb372:master Jul 31, 2020
@cb372
Copy link
Owner

cb372 commented Jul 31, 2020

It finally happened! Merged! 🚀

@cb372 cb372 mentioned this pull request Jul 31, 2020
4 tasks
@kubukoz
Copy link
Collaborator Author

kubukoz commented Jul 31, 2020

Wow, thanks a lot for making it happen @lewisjkl @cb372! I'm sorry I didn't get this to the end...

@kubukoz kubukoz deleted the cats-effect branch July 31, 2020 16:23
@lewisjkl
Copy link
Collaborator

Wow, thanks a lot for making it happen @lewisjkl @cb372! I'm sorry I didn't get this to the end...

No worries! Thanks for helping out so much with the refactor.

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.

Remove Cache Implementations
4 participants