-
Notifications
You must be signed in to change notification settings - Fork 4.3k
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
JSON configuration persistence #17
Conversation
import java.util.Set; | ||
|
||
public interface ConfigPersistence { | ||
<T> T getStandardConfig( |
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.
lmk if there's a better way to do the generics here. ultimately the jackson library needs to interact with a Class
object and i didn't want to do any reflection.
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.
So far so good!
|
||
public interface ConfigPersistence { | ||
<T> T getConfig( | ||
PersistenceConfigType persistenceConfigType, String configId, Class<T> clazz); |
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.
What is the purpose of PersistenceConfigType
if we already provide clazz
?
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.
good question. clazz
was a compromise implementation detail to get stuff to work. wish i could just get rid of that. if i drop the enum then the internals are going to have to do clazz.toString()
and then run it through some switch statement. i think retaining the enum still makes what's going on clearer.
|
||
import java.util.Set; | ||
|
||
public interface ConfigPersistence { |
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.
Should all these methods throw
so we can provide appropriate messages on the UI if needed?
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.
what do you want them to throw? right now i am catching all I/O exceptions internally and trying to put reasonable error messages.
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 we have a throw
in the signature of the methods, then the server has to handle exceptions well. Unless the impl you're going for is that these methods would throw reasonable messages and the server autowraps any failures nicely in a 500/400 in the UI? (and therefore doesn't need to wrap each individual failure)
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.
server autowraps any failures nicely in a 500/400
was not planning to do this.
can you give an example of what behavior you want? specifically what error you expect to have thrown and how the ui would interact with 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.
if a config file is formatted incorrectly (fails validation), the UI should display a message saying for example: file is corrupt
. Or if it is not found, should say file not found, please make sure your mount point is setup correctly
. I'm imagining that since the server would be calling this persistence class, if the persistence class fails, we want to respond to the UI with a 400/500 with a human-readable message. I see two ways of doing this:
- every method
throws
, and the server wraps that and throws based on position of the failure in control flow. This is higher friction since theUIserver must try-catch persistence operations. - throw all un-fixable exceptions at the lowest level, and in the server whenever an exception is thrown, respond with a 500 whose message is exactly the failure message of the thrown exception
It seems like this impl is leaning towards no.2 above? this seems like a good choice since it's lowest friction.
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 i punt on this until write some API endpoints and have a better feel for what will be ergonomic?
...-config-persistence/src/main/java/io/dataline/conduit/persistence/ConfigPersistenceImpl.java
Show resolved
Hide resolved
try { | ||
objectMapper.writeValue(new File(getConfigPath(persistenceConfigType, configId)), config); | ||
} catch (IOException e) { | ||
throw new RuntimeException(e); |
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.
Shouldn't these methods throw an IOException
instead of rethrowing as a runtime exception?
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 i punt on this until write some API endpoints and have a better feel for what will be ergonomic?
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.
Sounds good.
return String.format("%s.json", id); | ||
} | ||
|
||
private ConfigSchema standardConfigTypeToConfigSchema( |
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.
What's the purpose of having two enums that are identical instead of just one?
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.
ConfigSchema
is mapping for name to file path. PersistenceConfigType
is mean to be used as part of the interface but not tied to a file path.
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.
Is there any expectation for these to diverge in the future? This sort of switch/mapping feels like a bit of an antipattern.
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.
not sure yet. i'm already regretting custom json disk persistence due to lack of ability to query by anything other than id.
@@ -31,4 +31,5 @@ dependencies { | |||
} | |||
|
|||
jsonSchema2Pojo { | |||
targetPackage = 'io.dataline.conduit.conduit_config' |
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.
Late to the party but it is weird to have conduit repeated twice. why not io.dataline.conduit.config
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.
was just pattern matching other module names. the extra namespace can be dropped.
@@ -4,4 +4,4 @@ include 'conduit-api' | |||
include 'conduit-server' | |||
include 'conduit-commons' | |||
include 'conduit-config' | |||
|
|||
include 'conduit-config-persistence' |
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 did you decide to create an other module and not put it in conduit-config
?
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.
so that the json to pojo codegen can be isolated in a single package and then universally consumed externally.
In response to feedback on this PR #17 and after fiddling around with what implementing some endpoints looks like, I've made two updates to the configuration persistence: * The whole class is synchronized, to try to avoid any concurrency issues in the MVP. * Added a couple exception to the persistence interface. The philosophy I used here was that * we expose named exceptions that are actionable to the user. e.g. config not found, or you are trying to insert or access a config that does not pass validation. * we do NOT expose named exceptions related to the internal of the database (e.g. data corruption or we can't access the disk). we let these get handled as runtime exceptions.
This PR creates an interface and implementation for how to persist configuration objects. Start with
conduit-config-persistence/src/main/java/io/dataline/conduit/persistence/ConfigPersistence.java
andconduit-config-persistence/src/main/java/io/dataline/conduit/persistence/ConfigPersistenceImpl.java
.The other changes in this PR are mostly just tweaks to the json schema.