Search code examples
servicewso2abstractionballerina

Getting Concurrency Issue in Implementation


Package Level

PM.bal

public type PM object {

    public isolated function methodA(json config) returns error|http:Response;
    public isolated function methodB(json config) returns error|http:Response;
    public isolated function methodC(json config) returns sql:Client|error;
};

DefaultImplPM.bal

public class DefaultImplPM {
    *PM;
   
    public isolated function methodC(json config) returns sql:Client|error {
        return  new mysql:Client("dbConfig.host", "dbConfig.username", "dbConfig.password", "dbConfig.database");
    }

    public isolated function methodA(json config) returns error|http:Response {
        http:Response response = new;
        response.setJsonPayload("Default methodA is not implemented yet");
        return response;
    }

    public isolated function methodB( json config) returns error|http:Response {
        http:Response response = new;
        response.setJsonPayload("Default methodB is not implemented yet");
        return response;
    }
}

Service level

newImpl.bal

import package as pkg;
public class NewImplPM {
    *pkg:PM;
   
    public isolated function methodC(json config) returns sql:Client|error {
        return  new mysql:Client("dbConfig.host", "dbConfig.username", "dbConfig.password", "dbConfig.database");
    }

    public isolated function methodA(json config) returns error|http:Response {
        http:Response response = new;
        response.setJsonPayload("new methodA is not implemented yet");
        return response;
    }

    public isolated function methodB(json config) returns error|http:Response {
        http:Response response = new;
        response.setJsonPayload("new methodB is not implemented yet");
        return response;
    }
}

in service.bal

import package as pkg;

service /fr on new http:Listener(9090) {

    pkg:PM pmVariable;
    public function init() {
        self.pmVariable = new DefaultImplPM();
    }


    resource isolated function post methodD(string c) returns error|http:Response {
        return self.pmVariable.methodA(c);   
    }

    resource isolated function post methodE(string c) returns error|http:Response {
        return self.pmVariable.methodB(c);
    }
}

I have some abstract methods for a use case which may have multiple different types of implementation for those methods. I want to given an basic implementation in a ballerina package level. That will be my default algorithm. When some one wants to give some additional support with a new algorithm implementation in service level. He/She should be able to do it by including my interface and implement those methods.

With this implementation, I got concurrent calls will not be made to this method since the service is not an 'isolated' service warning. How to resolve this.


Solution

  • As indicated by the warning, this is because the service object is not isolated (nor does it meet the requirements for an isolated object to be inferred as one). Concurrent calls will be made to a resource method only if both the object and the method are isolated. If the object is not isolated, there can still be unsafe access of mutable state.

    See concurrency safety, specifically isolated objects.

    This service is not inferred as isolated since it has a non-private mutable field (which is also not accessed within locks, does not meet transfer in/out conditions for an isolated object, etc.).

    You can explicitly mark the service declaration to identify and fix what's causing it to be non-isolated.

    isolated service /fr on new http:Listener(9090) {
        ...
    }
    

    Generally, you would either have to

    1. make PM an isolated object and pmVariable a final field or
    2. make pmVariable a private field and use locks when accessing it and introduce related changes (to ensure that the object is an isolated root)