Регистрация  |  Вход

простой семафор

кто нибудь сталкивался с простейшей задачей разграничения ресурса и толково решил ее в СФ реалиях?

есть 1 админ пользователь, OAUTH 2.0 аутентификация, действие должно происходить по нажатию кнопки. В случае второго логина, пока первая сессия активна, обе сессии принудительно закрываются и токен теряется.
нельзя сделать DML до callout, так что я сделал 2 контекста под 1 кнопкой:
первый сохраняет custom setting как "in use"
второй делает все дела с логином и высвобождает

{!REQUIRESCRIPT("/soap/ajax/10.0/connection.js")} 
{!REQUIRESCRIPT("/soap/ajax/10.0/apex.js")}

var ProjectRef="{!обьект.Id}".toString();

var strResult = sforce.apex.execute("MYServiceName","getCredentials",{});

if(strResult != 'success')
{
alert(strResult );
}
else
{
var strResult = sforce.apex.execute("MYServiceName","MyRealMethod",{ProjectId:ProjectRef});
alert(strResult );
}

webservice static string getCredentials()
{
string theResult='';
IntegrationService Service = new IntegrationService();
кастум_сеттинг apiInfo = сервис.getSharingBoxAPIInfo();
if(apiInfo!=null)
{
if(apiInfo.In_use__c==false)
{
apiInfo.In_use__c=true;
update apiInfo;
theResult='success';
}
else
{
theResult='Another session is in progress. Try again later.';
}
}
else
{
theResult='Service login/password not found. Please contact your system Administrator.';
}
return theResult;
}

второй метод не привожу там просто логика и высвобождение независимо от результата

я так понимаю for update бесполезен т.к.
While the records are locked by a client, the locking client can modify their field values in the database in the same transaction. Other clients have to wait until the transaction completes and the records are no longer locked before being able to update the same records. Other clients can still query the same records while they’re locked.

т.к. это java script пользователи таки умудряются зажать мой семафор примерно раз в 2-3 месяца. нужно потерять интернет в очень нужную милисекунду когда первый реквест был послан а второй еще нет, или еще что нибудь подобное, так что метод явно не лишен недостатков.
поискал в интернете - http://salesforce.stackexchange.com/questions/24152/enforcing-mutual-exclusion-in-apex
вариант 2 описывает именно моё решение.
Есть какие другие варианты чтобы решение было 100% а не 99.999% ?

пока придумал только ночью во время 1 из batch процессов который занимает час, проверять вначале и в конце и если оба раза "in use" то снимать чекбокс.

кто нибудь сталкивался с простейшей задачей разграничения ресурса и толково решил ее в СФ реалиях?

есть 1 админ пользователь, OAUTH 2.0 аутентификация, действие должно происходить по нажатию кнопки. В случае второго логина, пока первая сессия активна, обе сессии принудительно закрываются и токен теряется.
нельзя сделать DML до callout, так что я сделал 2 контекста под 1 кнопкой:
 первый сохраняет custom setting как "in use"
 второй делает все дела с логином и высвобождает

[code]{!REQUIRESCRIPT("/soap/ajax/10.0/connection.js")} 
{!REQUIRESCRIPT("/soap/ajax/10.0/apex.js")} 

var ProjectRef="{!обьект.Id}".toString(); 

var strResult = sforce.apex.execute("MYServiceName","getCredentials",{}); 

if(strResult != 'success') 
{ 
alert(strResult ); 
} 
else 
{ 
var strResult = sforce.apex.execute("MYServiceName","MyRealMethod",{ProjectId:ProjectRef}); 
alert(strResult ); 
}
[/code]

[code]    webservice static string getCredentials()
    {
        string theResult='';
        IntegrationService Service = new IntegrationService();
        кастум_сеттинг apiInfo = сервис.getSharingBoxAPIInfo();
        if(apiInfo!=null)
        {
            if(apiInfo.In_use__c==false)
            {
                apiInfo.In_use__c=true;
                update apiInfo;
                theResult='success';
            }
            else
            {
                theResult='Another session is in progress. Try again later.';
            }
        }
        else
        {
            theResult='Service login/password not found. Please contact your system Administrator.';
        }
        return theResult;
    }[/code]
второй метод не привожу там просто логика и высвобождение независимо от результата

я так понимаю [b]for update[/b] бесполезен т.к.
While the records are locked by a client, the locking client can modify their field values in the database in the same transaction. Other clients have to wait until the transaction completes and the records are no longer locked before being able to update the same records. [b]Other clients can still query the same records while they’re locked.[/b]

т.к. это java script пользователи таки умудряются зажать мой семафор примерно раз в 2-3 месяца. нужно потерять интернет в очень нужную милисекунду когда первый реквест был послан а второй еще нет, или еще что нибудь подобное, так что метод явно не лишен недостатков. 
поискал в интернете - http://salesforce.stackexchange.com/questions/24152/enforcing-mutual-exclusion-in-apex
вариант 2 описывает именно моё решение.
Есть какие другие варианты чтобы решение было 100% а не 99.999% ?

пока придумал только ночью во время 1 из batch процессов который занимает час, проверять вначале и в конце и если оба раза "in use" то снимать чекбокс.

хм почитал еще раз про for update, походу можно воспользоваться всё же в данном случае, при условии что будет лочить custom setting, мдаааааа, надо попробовать

хм почитал еще раз про for update, походу можно воспользоваться всё же в данном случае, при условии что будет лочить custom setting, мдаааааа, надо попробовать 

Дабы 100%, то нужно все переводить в один контекст, что описали с асинхронной очередью в предложенных решениях. Учитывая тормознутость очереди, под твои задачи оно вряд ли подойдет.

В твоем бы случае я бы испробовал следующие опции:

1) Ассинхронная задача. Просто забить и добавить Queuable джоб, который бы рекурсивно "планировал" себя по окончанию обработки.
2) Лочил бы кастом сеттинг при запросе. Добавив один DML после запроса, но перед проверкой на "In Use" можно эмулировать лок на чтение.
3) Platform Cache. Для персистентного хранения естественно не подходит, но можно попробовать использовать его как буффер перед чтением, дабы близкие контексты "узнали" друг о друге. Выглядит покостыльнее других, ну хоть новую фичу пощупать можно.

Дабы 100%, то нужно все переводить в один контекст, что описали с асинхронной очередью в предложенных решениях. Учитывая тормознутость очереди, под твои задачи оно вряд ли подойдет. 

В твоем бы случае я бы испробовал следующие опции:

1) Ассинхронная задача. Просто забить и добавить Queuable джоб, который бы рекурсивно "планировал" себя по окончанию обработки. 
2) Лочил бы кастом сеттинг при запросе. Добавив один  DML после запроса, но перед проверкой на "In Use" можно эмулировать лок на чтение. 
3) Platform Cache. Для персистентного хранения естественно не подходит, но можно попробовать использовать его как буффер перед чтением, дабы близкие контексты "узнали" друг о друге. Выглядит покостыльнее других, ну хоть новую фичу пощупать можно. 



хех ктото даже читает

асинхронная задача с Queuable не подходит потому что это реал тайм - нажал кнопку - получил результат. Была имплементация на кнопке именно потому что надо мгновенно. На самом деле пользователей около 20 так что в реальности они не так часто получают ошибку сессии.

почитал про platform cache
Platform Cache Considerations
There are a few considerations for using platform cache features.
1 Cache is not persisted. There is no guarantee against data loss.
2 The cache doesn’t support concurrent operations. Multiple, simultaneous user requests (for example, from different browser windows) can lead to stale or overwrritten data in the cache.
3 Cache misses can happen. We recommend constructing your code to consider a case where previously cached items aren’t found.
как бы не подходит пока, совсем

остается только сделать query for update вначале транзакции и если получу exception то вернуть ошибку сессии пользователю.
с тех пор как я вопросом оптимизации занялся тут на работе просто сдвиг произошел и появились задачи поважнее чем старое переделывать, попробую позже на неделе.

хех ктото даже читает :)

асинхронная задача с Queuable не подходит потому что это реал тайм - нажал кнопку - получил результат. Была имплементация на кнопке именно потому что надо мгновенно. На самом деле пользователей около 20 так что в реальности они не так часто получают ошибку сессии.

почитал про platform cache 
Platform Cache Considerations
There are a few considerations for using platform cache features.
1 Cache is not persisted. There is no guarantee against data loss.
2 The cache doesn’t support concurrent operations. Multiple, simultaneous user requests (for example, from different browser windows) can lead to stale or overwrritten data in the cache.
3 Cache misses can happen. We recommend constructing your code to consider a case where previously cached items aren’t found.
как бы не подходит пока, совсем

остается только сделать query for update вначале транзакции и если получу exception то вернуть ошибку сессии пользователю.
с тех пор как я вопросом оптимизации занялся тут на работе просто сдвиг произошел и появились задачи поважнее чем старое переделывать, попробую позже на неделе.

Андрей
хех ктото даже читает

асинхронная задача с Queuable не подходит потому что это реал тайм - нажал кнопку - получил результат. Была имплементация на кнопке именно потому что надо мгновенно. На самом деле пользователей около 20 так что в реальности они не так часто получают ошибку сессии.

Асинхронную задачу предлагал использовать впараллель текущей имплементации. Просто мониторит текущие сессии на предмет "подвиса". То же самое что ты сам предложил делать батчем - только более частозапускаемое.

Андрей
почитал про platform cache

Ну да, как бы они просто говорят, что это кэш - его можно легко перезаписать, или поймать "несвежим".
Тут просто было бы интересно его попробовать в подобном сценарии и сравнить насколько он "оперативнее" обычного DML.
Сессию все равно хранить в сеттинге, а кэш использовать для проверки, ведь в него ты можешь положить и время когда значение было изменено и сверяться с ним на "входе" и "выходе" из процедуры.

Выглядить будет страшно, но попробовать забавно, было бы время.

[quote="Андрей"]хех ктото даже читает :)

асинхронная задача с Queuable не подходит потому что это реал тайм - нажал кнопку - получил результат. Была имплементация на кнопке именно потому что надо мгновенно. На самом деле пользователей около 20 так что в реальности они не так часто получают ошибку сессии.

[/quote]

Асинхронную задачу предлагал использовать впараллель текущей имплементации. Просто мониторит текущие сессии на предмет "подвиса". То же самое что ты сам предложил делать батчем - только более частозапускаемое. 

[quote="Андрей"]

почитал про platform cache 

[/quote]

Ну да, как бы они просто говорят, что это кэш - его можно легко перезаписать, или поймать "несвежим". 
Тут просто было бы интересно его попробовать в подобном сценарии и сравнить насколько он "оперативнее" обычного DML. 
Сессию все равно хранить в сеттинге, а кэш использовать для проверки, ведь в него ты можешь положить и время когда значение было изменено и сверяться с ним на "входе" и "выходе" из процедуры. 

Выглядить будет страшно, но попробовать забавно, было бы время.