Let's say we have a bidding system (written in Java 8), that according to some algorithm (bidding strategy) and certain conditions, we would increase or decrease the amount of the bid at a certain moment. We have different defined algorithms, but now we would like our users to define their own algorithm.

The user can choose between our algorithms which one he wants for his bid strategy.

The idea is to let them write code and then save this algorithm as a new option (among all our algorithms) to use in their bid strategy.

So, I thinked in this two options:

  1. Allow the user to write java code, save it in DB, and when the algorithm needs to be executed, compile that "String" (at run time) and execute it.

  2. Allow our users to write in an interpreted language, save it in DB, and when the algorithm requires to be executed, simply interpret each line, and publish the result in a queue that our "engine" would listen to.

Option 2 may not be a good idea, since may be millions of bids per user, so there may be too much latency in that approach. But I would like to know if 1 and 2 are a good approach or there is a better way to handle this requirement?

  • Are those users proeficent enough to make efficent algorithm that won't crash the database/server ? Probably not, so I would try either to explain why this is a bad idea or provide the strict minimum to try to have users not screwed up the server. Another idea would be a graphical languages of boxes, you would have whole control over it and may be able to limit the damage more easily. – Walfrat Apr 26 at 14:06
up vote 7 down vote accepted

This is a difficult problem: how can such user-provided code be executed securely, and how can you ensure a good user experience?

If you run code on behalf of someone else, you can't trust that code. The code may try to hog computing resources (thus incurring costs for you and denying computing resources to other bidders), may try to hack your system or the code of other bidders, or may simply use the computing resources you provide as part of a botnet … the possibilities for abuse are endless. So you need to sandbox this code very tightly. The Java security model is a good start, and allows you to deny reflection and other APIs to untrusted code. However, you may still find it difficult to reliably limit the available computing resources.

The next problem is user experience. How can users write, debug, and test their code? Will you provide a kind of IDE? Which APIs do you offer to that code? How is it documented? Is there a test environment where bidding strategies can be tried out? How will you gather and display error messages?

If you compile Java code, you are limited by the Java security model. This may actually be sufficient, assuming that you are proficient with that security model (I am not) and can configure it appropriately. You could easily cache the compiled code, so that it doesn't have to be re-compiled for each execution. There is mature tooling around Java, so it would be straightforward to offer a kind of IDE.

If you use any other JVM-based language such as Groovy, the same considerations apply. In the end, everything will end up as JVM bytecode and will therefore be reasonably fast.

If you integrate a non-JVM scripting language (either an existing language such as JavaScript or a DSL of your own design) then you have more control over the security boundary between your code and the untrusted user code. However, this might be a bit slower. In particular, implementing your own DSL is usually quite error-prone and often slow.

If an in-process sandbox is insufficient for your needs, consider process-level or operating-system-level sandboxes: containerization and virtualization. You would run user code in a separate process, and communicate over a socket. This doesn't just improve security, it also enables more scalability. However, any input/output must be serialized, which can limit performance.

Instead of building a textual DSL, you could also design a rule engine. Basically, you would provide configurable blocks that users can combine in a GUI. This is more accessible to non-programmers. By offering or not offering certain blocks (such as loops, function declarations, …) you can influence how expensive the resulting programs will be, while still offering more flexibility than a set of pre-configured strategies. As you control all available blocks, you can also create a clear security boundary without having to use complicated isolation features.

Unless your bids have to be resolved within seconds, there is another option: offer a REST API. That way, you don't have to execute any untrusted code. There is very mature tooling for creating APIs. There is a very clear security boundary. You can easily rate-limit excessive users. With an API, users could subscribe to a feed of events and react by posting their actions to your API endpoints. They are then totally free in how they write their strategies. However, they will have to provide their own computing resources. Whether this is a viable alternative depends largely on your market: is your product intended for consumers, or is it B2B or for developers?

But whatever you choose, other considerations like offering a usable testing environment can be much more complicated than just integrating a scripting language or offering an API.

I would suggest to ask yourself and/or clarify with stakeholders:

  1. What kind of flexibility is needed, and what are the possibilities for abuse with that flexibility?
  2. Is a rule engine sufficient to provide the needed flexibility?
  3. If not, would an API be appropriate?
  4. If not, which programming/scripting language would be the best user experience? E.g. Java, Groovy, JavaScript, or a custom DSL? Many performance problems can be solved by throwing money at the problem (using more servers), so performance should not be your first consideration here.
  • Great answer! Rule engine was the term which came first to my mind. – Thomas Junk Apr 26 at 14:24

Both options are perfectly reasonable but Option 1 would be more efficient overall for your scenario.

Compiling requires a noticeable one-time overhead (on the order of 0.1 sec) but does lead to significantly faster execution. If you're executing a strategy millions of times, then compiling will pay off in the long run. Just make sure that you aren't compiling millions of times!

You might not want to compile after extracting the String from the DB. You can compile beforehand and instead save the .class file in the DB. This will allow you to start executing the first few bids faster.

Your Answer

By clicking "Post Your Answer", you acknowledge that you have read our updated terms of service, privacy policy and cookie policy, and that your continued use of the website is subject to these policies.

Not the answer you're looking for? Browse other questions tagged or ask your own question.