Hi Jan! You can also add an additional class path URL to take classes from. Does that help? Is there a directly where the generated class files go, so that a local file URL could reference them and add them to the user code class loader?
Best, Stephan On Tue, Sep 10, 2019 at 10:28 AM Till Rohrmann <trohrm...@apache.org> wrote: > Hi Jan, > > sorry for my late response. I think the main concern about using the > context class loader is the unpredictability and magic it adds to a > component where you actually don't wanna be surprised. Moreover, if we now > add support for the context class loader, then at a later time another > component might use this feature as well. This component would then have to > make sure that the new class loader it sets has the current context class > loader as its parent because otherwise it might break your use case. > > But on the other hand, I admit that I don't have a good solution to your > problem at hand other than using the RemoveExecutionEnvironment. > > One comment concerning your proposed class loader resolution. I think it > adds a bit too much magic which is hard to understand for the user. It > would be better if the system would fail with a descriptive error message > instead. > > Cheers, > Till > > On Thu, Sep 5, 2019 at 12:55 PM Jan Lukavský <je...@seznam.cz> wrote: > > > Hi Till and Aljoscha, > > > > I was investigating the other options, but unfortunately all of them > > look a little complicated (although possible, of course). But before > > going into a more complicated solutions, I'd like to know what issues do > > you actually see with using the context class loader. I can think of one > > difficulty - if (for whatever reason), the context class loader doesn't > > contain (in itself or as a parent) class loader that loaded flink core > > classes, that would probably cause troubles. So, what about a solution > > that we take as parent class loader of FlinkUserCodeClassLoaders a class > > loader that is: > > > > a) context class loader of current thread, if it either is actually > > class loader of flink core classes, or if it contains this class loader > > in its parent hierarchy, or > > > > b) class loader of flink core classes > > > > That way, class loader of flink core classes would always be in parent > > hierarchy of FlinkUserCodeClassLoaders. Would that solve the issues you > > see? It works for me. > > > > Jan > > > > On 9/3/19 4:52 PM, Jan Lukavský wrote: > > > Answers inline. > > > > > > On 9/3/19 4:01 PM, Till Rohrmann wrote: > > >> How so? Does your REPL add the generated classes to the system class > > >> loader? I assume the system class loader is used to load the Flink > > >> classes. > > > No, it does not. It cannot on JDK >= 9 (or would have to hack into > > > jdk.internal.loader.ClassLoaders, which I don't want to :)). It just > > > creates another class loader, and is able to create a jar from > > > generated files. The jar is used for remote execution. > > >> > > >> Ideally, what you would like to have is the option to provide the > parent > > >> class loader which is used load user code to the LocalEnvironment. > > >> This one > > >> could then be forwarded to the TaskExecutor where it is used to > generate > > >> the user code class loader. But this is a bigger effort. > > > I'm not sure how this differs from using context classloader? Maybe > > > there is subtle difference in that this is a little more explicit. On > > > the other hand, users normally do not modify class loaders, so the > > > practical impact is IMHO negligible. But maybe this opens another > > > possibility - we probably could add optional ClassLoader parameter to > > > LocalEnvironment, with default value of > > > FlinkRunner.class.getClassLoader()? That might be a good compromise. > > >> > > >> The downside to this approach is that it requires you to create a jar > > >> file > > >> and to submit it via a REST call. The upside is that it is closer to > the > > >> production setting. > > > > > > Yes, a REPL has to do that anyway to support distributed computing, so > > > this is not an issue. > > > > > > Jan > > > > > >> > > >> Cheers, > > >> Till > > >> > > >> On Tue, Sep 3, 2019 at 3:47 PM Jan Lukavský <je...@seznam.cz> wrote: > > >> > > >>> On the other hand, if you say, that the contract of LocalEnvironment > is > > >>> to execute as if it had all classes on its class loader, then it > > >>> currently breaks this contract. :-) > > >>> > > >>> Jan > > >>> > > >>> On 9/3/19 3:45 PM, Jan Lukavský wrote: > > >>>> Hi Till, > > >>>> > > >>>> hmm, that sounds it might work. I would have to incorporate this > > >>>> (either as default, or on demand) into Apache Beam. Would you see > any > > >>>> disadvantages of this approach? Would you suggest to make this > default > > >>>> behavior for local beam FlinkRunner? I can introduce a configuration > > >>>> option to turn this behavior on, but that would bring additional > > >>>> maintenance burden, etc., etc. > > >>>> > > >>>> Jan > > >>>> > > >>>> On 9/3/19 3:38 PM, Till Rohrmann wrote: > > >>>>> I see the problem Jan. What about the following proposal: Instead > of > > >>>>> using > > >>>>> the LocalEnvironment for local tests you always use the > > >>>>> RemoteEnvironment > > >>>>> but when testing it locally you spin up a MiniCluster in the same > > >>>>> process > > >>>>> and initialize the RemoteEnvironment with > > >>>>> `MiniCluster#getRestAddress`. > > >>>>> That way you would always submit a jar with the generated classes > > >>>>> and, > > >>>>> hence, not having to set the context class loader. > > >>>>> > > >>>>> The contract of the LocalEnvironment is indeed that all classes it > is > > >>>>> supposed t execute must be present when being started. > > >>>>> > > >>>>> Cheers, > > >>>>> Till > > >>>>> > > >>>>> On Tue, Sep 3, 2019 at 2:27 PM guaishushu1...@163.com < > > >>>>> guaishushu1...@163.com> wrote: > > >>>>> > > >>>>>> > > >>>>>> > > >>>>>> guaishushu1...@163.com > > >>>>>> > > >>>>>> From: guaishushu1...@163.com > > >>>>>> Date: 2019-09-03 20:25 > > >>>>>> To: dev > > >>>>>> Subject: Re: Re: ClassLoader created by BlobLibraryCacheManager > > >>>>>> is not > > >>>>>> using context classloader > > >>>>>> > > >>>>>> > > >>>>>> > > >>>>>> > > >>>>>> guaishushu1...@163.com > > >>>>>> From: guaishushu1...@163.com > > >>>>>> Date: 2019-09-03 20:23 > > >>>>>> To: dev > > >>>>>> Subject: Re: Re: ClassLoader created by BlobLibraryCacheManager > > >>>>>> is not > > >>>>>> using context classloader > > >>>>>> guaishushu1...@163.com > > >>>>>> From: Jan Lukavský > > >>>>>> Date: 2019-09-03 20:17 > > >>>>>> To: dev > > >>>>>> Subject: Re: ClassLoader created by BlobLibraryCacheManager is not > > >>>>>> using > > >>>>>> context classloader > > >>>>>> Hi Till, > > >>>>>> the use-case is pretty much simple - I have a REPL shell in > groovy, > > >>>>>> which generates classes at runtime. The actual hierarchy is > > >>>>>> therefore > > >>>>>> system class loader -> application classloader -> repl classloader > > >>>>>> (GroovyClassLoader actually) > > >>>>>> now, when a terminal (sink) operation in the shell occurs, I'm > > >>>>>> able to > > >>>>>> build a jar, which I can submit to remote cluster (in distributed > > >>>>>> case). > > >>>>>> But - during testing - I run the code using local flink. There > > >>>>>> is no > > >>>>>> (legal) way of adding this new runtime generated jar to local > > >>>>>> flink. As > > >>>>>> I said, I have a hackish solution which works on JDK <= 8, > > >>>>>> because it > > >>>>>> uses reflection to call addURL on the application classloader (and > > >>>>>> thefore "pretends", that the generated jar was there all the time > > >>>>>> from > > >>>>>> the JVM startup). This breaks on JDK >= 9. It might be possible > > >>>>>> to work > > >>>>>> around this somehow, but I think that the reason why > > >>>>>> LocalEnvironment is > > >>>>>> not having a way to add jars (as in case of RemoteEnvironment) is > > >>>>>> that > > >>>>>> is assumes, that you actually have all of the on classpath when > > >>>>>> using > > >>>>>> local runner. I think that this implies that it either has to use > > >>>>>> context classloader (to be able to work on top of any > > >>>>>> classloading user > > >>>>>> might have), or is wrong and would need be fixed, so that > > >>>>>> LocalEnvironment would accept files to "stage" - which would mean > > >>>>>> adding > > >>>>>> them to a class loader (probably URLClassLoader with the > application > > >>>>>> class loader as parent). > > >>>>>> Or, would you see any other option? > > >>>>>> Jan > > >>>>>> On 9/3/19 2:00 PM, Till Rohrmann wrote: > > >>>>>>> Hi Jan, > > >>>>>>> > > >>>>>>> I've talked with Aljoscha and Stephan offline and we concluded > > >>>>>>> that we > > >>>>>>> would like to avoid the usage of context class loaders if > possible. > > >>>>>>> The > > >>>>>>> reason for this is that using the context class loader can easily > > >>>>>>> mess up > > >>>>>>> an otherwise clear class loader hierarchy which makes it hard to > > >>>>>>> reason > > >>>>>>> about and to debug class loader issues. > > >>>>>>> > > >>>>>>> Given this, I think it would help to better understand the exact > > >>>>>>> problem > > >>>>>>> you are trying to solve by using the context class loader. > > >>>>>>> Usually the > > >>>>>>> usage of the context class loader points towards an API > deficiency > > >>>>>>> which > > >>>>>> we > > >>>>>>> might be able to address differently. > > >>>>>>> > > >>>>>>> Cheers, > > >>>>>>> Till > > >>>>>>> > > >>>>>>> On Mon, Sep 2, 2019 at 11:32 AM Aljoscha Krettek > > >>>>>>> <aljos...@apache.org > > >>>>>>> wrote: > > >>>>>>> > > >>>>>>>> I’m not saying we can’t change that code to use the context > class > > >>>>>> loader. > > >>>>>>>> I’m just not sure whether this might break other things. > > >>>>>>>> > > >>>>>>>> Best, > > >>>>>>>> Aljoscha > > >>>>>>>> > > >>>>>>>>> On 2. Sep 2019, at 11:24, Jan Lukavský <je...@seznam.cz> > wrote: > > >>>>>>>>> > > >>>>>>>>> Essentially, the class loader of Flink should be present in > > >>>>>>>>> parent > > >>>>>>>> hierarchy of context class loader. If FlinkUserCodeClassLoader > > >>>>>>>> doesn't > > >>>>>> use > > >>>>>>>> context class loader, then it is actually impossible to use a > > >>>>>>>> hierarchy > > >>>>>>>> like this: > > >>>>>>>>> system class loader -> application class loader -> > > >>>>>>>>> user-defined class > > >>>>>>>> loader (defines some UDFs to be used in flink program) > > >>>>>>>>> Flink now uses the application class loader, and so the UDFs > > >>>>>>>>> fail to > > >>>>>>>> deserialize on local flink, because the user-defined class > > >>>>>>>> loader is > > >>>>>>>> bypassed. Moreover, there is no way to add additional classpath > > >>>>>>>> elements > > >>>>>>>> for LocalEnvironment (as opposed to RemoteEnvironment). I'm able > > >>>>>>>> to hack > > >>>>>>>> this by calling addURL method on the application class loader > > >>>>>>>> (which is > > >>>>>>>> terribly hackish), but that works only on JDK <= 8. No sensible > > >>>>>> workaround > > >>>>>>>> is available for JDK >= 9. > > >>>>>>>>> Alternative solution would be to enable adding jars to class > > >>>>>>>>> loader > > >>>>>> when > > >>>>>>>> using LocalEnvironment, but that looks a little odd. > > >>>>>>>>> Jan > > >>>>>>>>> > > >>>>>>>>> On 9/2/19 11:02 AM, Aljoscha Krettek wrote: > > >>>>>>>>>> Hi, > > >>>>>>>>>> > > >>>>>>>>>> I actually don’t know whether that change would be ok. > > >>>>>>>> FlinkUserCodeClassLoader has taken > > >>>>>>>> FlinkUserCodeClassLoader.class.getClassLoader() as the parent > > >>>>>> ClassLoader > > >>>>>>>> before my change. See: > > >>>>>>>> > > >>> > > > https://github.com/apache/flink/blob/release-1.2/flink-runtime/src/main/java/org/apache/flink/runtime/execution/librarycache/FlinkUserCodeClassLoader.java > > >>> > > >>>>>>>> < > > >>>>>>>> > > >>> > > > https://github.com/apache/flink/blob/release-1.2/flink-runtime/src/main/java/org/apache/flink/runtime/execution/librarycache/FlinkUserCodeClassLoader.java > > >>> > > >>>>>>>>> . > > >>>>>>>>>> I have the feeling that this might be on purpose because we > > >>>>>>>>>> want to > > >>>>>>>> have the ClassLoader of the Flink Framework components be the > > >>>>>>>> parent > > >>>>>>>> ClassLoader, but I could be wrong. Maybe Stephan would be most > > >>>>>> appropriate > > >>>>>>>> for answering this. > > >>>>>>>>>> Best, > > >>>>>>>>>> Aljoscha > > >>>>>>>>>> > > >>>>>>>>>>> On 30. Aug 2019, at 16:28, Till Rohrmann < > trohrm...@apache.org > > > > > >>>>>> wrote: > > >>>>>>>>>>> Hi Jan, > > >>>>>>>>>>> > > >>>>>>>>>>> this looks to me like a bug for which you could create a JIRA > > >>>>>>>>>>> and PR > > >>>>>>>> to fix it. Just to make sure, I've pulled in Aljoscha who is the > > >>>>>>>> author > > >>>>>> of > > >>>>>>>> this change to check with him whether we are forgetting > something. > > >>>>>>>>>>> Cheers, > > >>>>>>>>>>> Till > > >>>>>>>>>>> > > >>>>>>>>>>> On Fri, Aug 30, 2019 at 3:44 PM Jan Lukavský < > je...@seznam.cz > > >>>>>> <mailto: > > >>>>>>>> je...@seznam.cz>> wrote: > > >>>>>>>>>>> Hi, > > >>>>>>>>>>> > > >>>>>>>>>>> I have come across an issue with classloading in Flink's > > >>>>>>>>>>> MiniCluster. > > >>>>>>>>>>> The issue is that when I run local flink job from a thread, > > >>>>>>>>>>> that has > > >>>>>> a > > >>>>>>>>>>> non-default context classloader (for whatever reason), this > > >>>>>> classloader > > >>>>>>>>>>> is not taken into account when classloading user defined > > >>>>>>>>>>> functions. > > >>>>>>>> This > > >>>>>>>>>>> is due to [1]. Is this behavior intentional, or can I file a > > >>>>>>>>>>> JIRA and > > >>>>>>>>>>> use Thread.currentThread.getContextClassLoader() there? I > have > > >>>>>>>> validated > > >>>>>>>>>>> that it fixes issues I'm facing. > > >>>>>>>>>>> > > >>>>>>>>>>> Jan > > >>>>>>>>>>> > > >>>>>>>>>>> [1] > > >>>>>>>>>>> > > >>> > > > https://github.com/apache/flink/blob/ce557839d762b5f1ec92aa1885fd3d2ae33d0d0b/flink-runtime/src/main/java/org/apache/flink/runtime/execution/librarycache/BlobLibraryCacheManager.java#L280 > > >>> > > >>>>>>>> < > > >>>>>>>> > > >>> > > > https://github.com/apache/flink/blob/ce557839d762b5f1ec92aa1885fd3d2ae33d0d0b/flink-runtime/src/main/java/org/apache/flink/runtime/execution/librarycache/BlobLibraryCacheManager.java#L280 > > >>> > > >