Multi-Threading MySQL/HTTP Operations

I am currently trying to multi-thread my MySQL and HTTP queries, but I can not think of a good way to do this. Does anyone have any good ideas on how I can multi-thread MySQL/HTTP?

Do you need to sync your queries??

Use the SchedulerService with an asynchronous task. Documentation pending here

1 Like

@Zirconium Thanks for the response.

I was questioning more on how to do the actual implementation

Say I have a method that gets some data from a database, and I want it to be run in a separate thread.

public String getMySQLData(String input) {
  //Run this method in a separate thread
  return response;
}

Is this possible to do?

Also, is the scheduler implemented yet?

Seems to be: https://github.com/SpongePowered/SpongeCommon/tree/master/src/main/java/org/spongepowered/common/service/scheduler

Using an async task you will get a task to run on another thread from a thread pool provided by the scheduler service.

1 Like

It is implemented. If you follow the documentation that I linked above, you should be able to get it working. You should just put that method in the run method of your implementation of the Runnable interface, and pass in the String input through the constructor

@Zirconium

Is there a way that I can return the string that is found?

No… the run method of a Runnable does not return anything. I could advise you as to how to pass around the String you get if you provide me with a bit more context.

@Zirconium

The method will be found in a utilities class in my plugin. It gets the player’s UUID from the Mojang’s servers. I call it from other classes by giving it the player name I want to lookup.

The method currently looks like this:

public String getUUID(String name) {
	JsonUtils jsonUtils = new JsonUtils();
	HttpUtils httpUtils = new HttpUtils();

        response = httpUtils.requestData("https://api.mojang.com/users/profiles/minecraft/"+name);
	
	return jsonUtils.parseToUUID(response);
}

So you want to call getUUID in a synchronous setting but have the actual method be called asynchronously? If so, you could make that method a Runnable, and schedule it asynchronously, then use a callback (see here for more info) to execute the rest of your code. Alternatively, I suppose you could also schedule a synchronous task at the completion of the asynchronous one and pass in the UUID of the player. A bit messy and over-complicated, but someone please let me know if there is a better way

EDIT: Never really tried to use callbacks in Java - only ever used them in JS, where they are a lot more natural as you can pass around functions as arguments.

1 Like

@Zirconium
I would like to avoid using callbacks if possible. Could you please explain scheduling the synchronous task at the completion of the async one a bit more?

Just as you originally scheduled the first asynchronous task, just pass in the SchedulerService to the constructor of the (asynchronous task) Runnable and use that to schedule a synchronous task.

@Zirconium

Thanks for all of the time you are taking to reply to me, but I don’t understand how I will return a value by scheduling a sync task.

Sorry about asking so many questions. I am just really struggling to understand things for some reason.

You’re fine!

String name = "Zirconium";
taskBuilder.execute(new GetUUIDRunnable(name)).async().submit(plugin);

So that will schedule your original asynchronous runnable

class GetUUIDRunnable implements Runnable {

    private String name;
    private MyPlugin plugin;

    public GetUUIDRunnable (String name, MyPlugin plugin) {
        this.name = name;
        this.taskBuilder = taskBuilder;
    }

    @Override
    public void run() {
        JsonUtils jsonUtils = new JsonUtils();
	HttpUtils httpUtils = new HttpUtils();

        response = httpUtils.requestData("https://api.mojang.com/users/profiles/minecraft/"+name);
        UUID uuid = jsonUtils.parseToUUID(response);

        // Obviously, you'd have to make a getGame method in your main plugin class
        TaskBuilder taskBuilder = plugin.getGame().getScheduler().getTaskBuilder();
        taskBuilder.execute(new WhateverIWantToDoNextRunnable(uuid)).submit(plugin);
    }
}

Then you get your UUID asynchronously, and schedule another (synchronous) task, specifying a Runnable which contains code for whatever else you need to do.

class WhateverIWantToDoNextRunnable implements Runnable {

    private UUID uuid;

    public WhateverIWantToDoNextRunnable(UUID uuid) {
        this.uuid = uuid
    }

    @Override
    public void run() {
    ...
    } 
}

Hope it helps

EDIT: Sorry if it doesn’t compile; I didn’t use an IDE or anything to check it, just wrote it up in the browser

@Zirconium
Thanks this help. One more question: So I can not make a method async I have make changes to the code that calls the method, is that correct?
What I mean if I have a call to my UUID method in my plugin, I can not just edit the method itself, I have to change the code that calls the UUID method.

If I’m understanding you correctly, you want to keep the method the same, but still run it asynchronously? You might want to look into promises (using JDeferred)

EDIT: That wouldn’t actually solve your problem. You’d still need to make your existing method into a Runnable, but it would make the code a bit cleaner

EDIT 2: I’m not seeing a good way of not changing the method… Someone else might have a better idea, but you might be best off just turning it into a Runnable

@Zirconium
I can’t see how I can return a value by using a runnable, do I have to use a callback?

That’s the only good way I can think of doing it… the code you need to execute after the async part has to be on the main thread, correct?

@Zirconium
I believe it should be. It will be interacting with a player object, which I don’t believe is thread-safe.

You can’t execute a method in a thread, run the method in a another thread and return the value in your thread. What do you want to do in the player?