2

Please note: Although this question mentions Java, I think it's an OOP/concurrency problem at heart and can probably be answered by anyone with significant programming experience.


So I'm building a ConfigurationLoader that will read Configuration POJO from a remote service and make it available via an API. A few things:

  • As soon as the ConfigurationLoader is asked for the Configuration the first time, a background thread (worker) will ping the remote service every, say, 30 seconds, for updates and then apply those updates to the Configuration instance; and
  • If the Configuration is modified, the background worker will be notified of the change and will push the "new" Configuration to the remote service;
  • Both the ConfigurationLoader and the Configuration must be thread-safe

So when I think "thread safety" the first thing I think of is immutability, which leads me towards excellent projects like Immutables. The problem is that Configuration can't be immutable because we need to be able to change it on the client-side and then let the loader ripple those changes back to the server.

My next thought was to try and make both ConfigurationLoader and Configuration singletons, but the problem is there is that the ConfigurationLoader takes a lot of arguments to instantiate it, and as this excellent answer points out, a singleton that takes arguments in construction is not a true singleton.

// Groovy pseudo-code
class Configuration {
    // Immutable? Singleton? Other?
}

class ConfigurationLoader {
    // private fields
    Configuration configuration

    ConfigurationLoader(int fizz, boolean buzz, Foo foo, List<Bar> bars) {
        super()

        this.fizz = fizz
        this.buzz = buzz;
        // etc.
    }

    Configuration loadConfiguration() {
        if(configuration == null) {
            // Create background worker that will constantly update
            // 'configuration'
        }
    }
}

What are my options here? How do I create both the loader and the config to be thread-safe, where the config is changeable by the client-side (on-demand) or asynchronously by a background worker thread?

Community
  • 1
  • 1
smeeb
  • 27,777
  • 57
  • 250
  • 447

2 Answers2

2

The problem is that Configuration can't be immutable because we need to be able to change it

It can still be immutable, you just create a new one for every change ("copy-on-write").

What are my options here?

First thing you'll have to think about: How do you want to react to configuration changes in concurrently running tasks? Basically, you have three options:

Ignore configuration change until the task is done

I.e. some directory your codes writes files to - finish writing the current file to the current target dir, put new files in the new dir. Writing some bytes into /new/path/somefile won't be a good idea if you never created that file. Your best option for this is probably an immutable Configuration object that you store in a field of your task instance (i.e. at task creation - in that case you can also make that field final for clarity). This usually works best if your code is designed as a collection of isolated small tasks.

Pros: Config never changes within a single task, so this is simple to get tread-safe and easy to test.

Cons: Config updates never make it to already running tasks.

Make your tasks check for config changes

I.e. your task regularly sends some data to an email address. Have a central storage for your config (like in your pseudo-code) and re-fetch it in some interval (i.e. between collecting data and sending the mail) from your task code. This usually works best for long-running/permanent tasks.

Pros: Config can change during a task run, but still somewhat simple to get safe - just make sure you have some memory barrier in place for reading the config (make your private configuration field volatile, use an AtomicReference, guard it with a lock, whatever).

Cons: Task code will be harder to test than first option. Config values may still be outdated between checks.

Signal config changes to your tasks

Basically option two, but the other way around. Whenever config changes, interrupt your tasks, handle the interrupt as a "config needs updating" message, continue/restart with new config.

Pros: Config values are never outdated.

Cons: This is the hardest to get right. Some might even argue that you cannot get this right, because interruption should only be used for task abortion. There is only very minor benefits (if at all) over the second option if you place your task's update checks at the right spots. Don't do this if you don't have a good reason to.

duckstep
  • 1,148
  • 8
  • 17
1

You need a singleton to pull this off, but your singleton isn't the immutable thing. Its the threadsafe thing. Make your singleton (Configuration) contain a simple Properties object or something and protect access to this with synchronization. Your Configuration Loader somehow knows of this Configuration singleton and functions to set, under synchronization, new instances of the Properties object when it detects change.

I'm pretty sure Apache Commons Configuration does something like this.

Bob Kuhar
  • 10,838
  • 11
  • 62
  • 115