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

Одностороняя real-time интеграция со стороним сервисом

Здраствуйте, столкнулся с темой интеграции, но ничего что б могло помоч начинающому не смог найти. Подскажите как можно реализовать real-time интеграцию.

Думал сделать schedule который будет вызывать batch, batch будет как-то брать даные со сторього сервиса, и потом делать обробку. А по завершению, в методе finish будет запускать следуюющий schedule, например через 15 минут.

Здраствуйте, столкнулся с темой интеграции, но ничего что б могло помоч начинающому не смог найти. Подскажите как можно реализовать real-time интеграцию. 

Думал сделать schedule который будет вызывать batch, batch будет как-то брать даные со сторього сервиса, и потом делать обробку. А по завершению, в методе finish будет запускать следуюющий schedule, например через 15 минут.

Да, это правильный подход.

Только Sheduler на надо запускать после окончания батча каждый раз. Просто ставишь sheduler на каждые 15 минут и все. А он уже запускает батч. Хотя в этом случае есть вероятность что батч не успеет отработать до очередного запуска sheduler - для этого можно предусмотреть проверку.

Но твой способ тоже рабочий, только чуть сложнее будет управлять sheduler.

Да, это правильный подход.

Только Sheduler на надо запускать после окончания батча каждый раз. Просто ставишь sheduler на каждые 15 минут и все. А он уже запускает батч. Хотя в этом случае есть вероятность что батч не успеет отработать до очередного запуска sheduler - для этого можно предусмотреть проверку.

Но твой способ тоже рабочий, только чуть сложнее будет управлять sheduler.

Dmitry Shnyrev
Только Sheduler на надо запускать после окончания батча каждый раз. Просто ставишь sheduler на каждые 15 минут и все. А он уже запускает батч. Хотя в этом случае есть вероятность что батч не успеет отработать до очередного запуска sheduler - для этого можно предусмотреть проверку.

Да, спасибо, так получается попроще реализация.

А кто уже делал интеграцию, или что-то в етом роде, какие есть подводние камни.

Вот я собираюсь в schedule делать callout, и в лимитах нашол что response или request не должны превишать 3 Мб, потому первий запуск интеграции свалится по лимитам.

[quote="Dmitry Shnyrev"]
Только Sheduler на надо запускать после окончания батча каждый раз. Просто ставишь sheduler на каждые 15 минут и все. А он уже запускает батч. Хотя в этом случае есть вероятность что батч не успеет отработать до очередного запуска sheduler - для этого можно предусмотреть проверку.[/quote]

Да, спасибо, так получается попроще реализация. 

А кто уже делал интеграцию, или что-то в етом роде, какие есть подводние камни. 

Вот я собираюсь в schedule делать callout, и в лимитах нашол что response или request не должны превишать 3 Мб,      потому первий запуск интеграции свалится по лимитам.

1) Еще на 10 callouts из одной точки входа...
А также полно здесь
http://www.salesforce.com/us/developer/docs/apexcode/Content/apex_callouts_timeouts.htm

2) Проблемы интеграции.
а) На какой из сторон ты будешь "парсить данные" (на обеих, или данные будут в "чистом виде приходить" или будут еще какие-то нюансы)
б) Как будут данные из внешней системы интегрироваться в SF. Будут ли какие-то внешние идендификаторы сущностей (External ID)
в) Объем данных (но ты уже говорил про это).
г) API. SOAP, REST ....etc.

1) Еще на 10 callouts из одной точки входа...
А также полно здесь
[url]http://www.salesforce.com/us/developer/docs/apexcode/Content/apex_callouts_timeouts.htm[/url]

2) Проблемы интеграции. 
    а) На какой из сторон ты будешь "парсить данные" (на обеих, или данные будут в "чистом виде приходить" или будут еще какие-то нюансы) 
    б) Как будут данные из внешней системы интегрироваться в SF. Будут ли какие-то внешние идендификаторы сущностей (External ID)
    в) Объем данных (но ты уже говорил про это).
    г) API. SOAP, REST ....etc.

Вот я собираюсь в schedule делать callout, и в лимитах нашол что response или request не должны превишать 3 Мб, потому первий запуск интеграции свалится по лимитам.

3мб это реальная проблема. Сталкивался с этим на реальном проекте. Приходилось разбивать запрашиваемые данные на мелкие пачки, что увеличивало количество итераций батча.

НО если проблема с 3мб всплывает, то это сигнал задуматься о задаче в общем. Зачем столько данных на стороне SF? Места под хранение данных на орге не так уж много и это чревато быстрой потерей свободного места. У меня так получилось - нужно было вытягивать данные (типо новости) с одного сервиса-парсера и сохранять их в кастомный объект. Так получилось что "новости" от сервиса были разного размера и в большинстве случаев большого. В итоге пара часов работы на реальных данных на боевом сервере (на тестовых данных, я про это не подумал - тестовых данных было мало) - орг был забил под завязку. Эта история в копилку знаний :)

[quote]Вот я собираюсь в schedule делать callout, и в лимитах нашол что response или request не должны превишать 3 Мб, потому первий запуск интеграции свалится по лимитам.[/quote]
3мб это реальная проблема. Сталкивался с этим на реальном проекте. Приходилось разбивать запрашиваемые данные на мелкие пачки, что увеличивало количество итераций батча.

НО если проблема с 3мб всплывает, то это сигнал задуматься о задаче в общем. Зачем столько данных на стороне SF? Места под хранение данных на орге не так уж много и это чревато быстрой потерей свободного места. У меня так получилось - нужно было вытягивать данные (типо новости) с одного сервиса-парсера и сохранять их в кастомный объект. Так получилось что "новости" от сервиса были разного размера и в большинстве случаев большого. В итоге пара часов работы на реальных данных на боевом сервере (на тестовых данных, я про это не подумал - тестовых данных было мало) - орг был забил под завязку. Эта история в копилку знаний :)

Совсем недавно наткнулся. Интересное исследование. Сколько весит запись в SF. Интересно, что оно не завист от количества информации и прочего.

Salesforce uses a simplistic method for calculating storage usage. Most records use 2KB of space despite how many fields are actually used. There are a few exceptions to this rule.

See "What are the various record sizes?" on Salesforce for which objects take more or less space.

Person Accounts - 4KB
Campaigns - 8KB
Campaign Members – 1KB
Articles - 4KB
Email Message - This is dependent upon the content of the messages, a 100kb email message takes 100kb of data storage space. Text only emails will take less than HTML due to only being the body text and not the html code and text version as well.
NOTE ABOUT PERSON ACCOUNTS Person Accounts consume a record in both the Account and Contact objects. Each record allocates 2KB, so each Person Account record will require 4KB of storage space. As an example, 500,000 person accounts will require 2GB (500,000 * 4KB) of storage. Images from Rich Text Fields are stored in file storage area.

Полно тут:
http://salesforce.stackexchange.com/questions/14174/how-does-salesforce-calculate-data-storage-usage-amount

Совсем недавно наткнулся. Интересное исследование. Сколько весит запись в SF. Интересно, что оно не завист от количества информации и прочего. 

Salesforce uses a simplistic method for calculating storage usage. Most records use 2KB of space despite how many fields are actually used. There are a few exceptions to this rule.

See "What are the various record sizes?" on Salesforce for which objects take more or less space.

Person Accounts - 4KB
Campaigns - 8KB
Campaign Members – 1KB
Articles - 4KB
Email Message - This is dependent upon the content of the messages, a 100kb email message takes 100kb of data storage space. Text only emails will take less than HTML due to only being the body text and not the html code and text version as well.
NOTE ABOUT PERSON ACCOUNTS Person Accounts consume a record in both the Account and Contact objects. Each record allocates 2KB, so each Person Account record will require 4KB of storage space. As an example, 500,000 person accounts will require 2GB (500,000 * 4KB) of storage. Images from Rich Text Fields are stored in file storage area.

Полно тут:
[url]http://salesforce.stackexchange.com/questions/14174/how-does-salesforce-calculate-data-storage-usage-amount[/url]

Очень правильное замечание (полезная информация) для тех кто планирует на Salesforce работать с БОЛЬШИМ количеством информации.

Очень правильное замечание (полезная информация) для тех кто планирует на Salesforce работать с БОЛЬШИМ количеством информации.

Вот возникла у меня проблема, есть Schedule, а в ньом мне нужно выполнить callaout, но проблема в том, что

Synchronous Web service callouts are not supported from scheduled Apex. To be able to make callouts, make an asynchronous callout by placing the callout in a method annotated with @future(callout=true) and call this method from scheduled Apex.

Получается, что всю логину нужно вешать на callaut method, а schedul будет просто визивать етот метод.

Как в таком случае коректно обработать exception(например, повторно отправить callout)?

Или лучше сделать Batch и из Schedule визивать Batch, а в ньому уже вся логика?

Вот возникла у меня проблема, есть Schedule, а в ньом мне нужно выполнить callaout, но проблема в том, что

[quote]Synchronous Web service callouts are not supported from scheduled Apex. To be able to make callouts, make an asynchronous callout by placing the callout in a method annotated with @future(callout=true) and call this method from scheduled Apex.[/quote]

Получается, что всю логину нужно вешать на callaut method, а schedul будет просто визивать етот метод. 

Как в таком случае коректно обработать exception(например, повторно отправить callout)?

Или лучше сделать Batch и из Schedule визивать Batch, а в ньому уже вся логика?

Я бы сделал так. Есть какой-то Scheduler (работающий 1 раз в 15 минут)

global class TestScheduler implements Schedulable{
global void execute(SchedulableContext SC) {
if(!Test.isRunningTest()) {
MyBatch.startBatch(DateTime.now());
}
System.abortJob(sc.getTriggerId());
run(DateTime.now());
}
}
public static void run(DateTime nextDate) {
String cronString = '0 ' + nextDate.addMinutes(15) + ' * * * ?'';
System.schedule('TestScheduler' + DateTime.now(), cronString, new TestScheduler ());
}

Я бы сделал так. И обрати внимание на MyBatch.startBatch(DateTime.now()); А в батче нечто следующее:

global class MyBatch implements Database.Batchable<sObject>, Database.Stateful  {

private Datetime startDate4Batch;

global PPTTrackerBatch(Datetime startDate4Batch) {
this.startDate4Batch = startDate4Batch;
}

public static void startBatch(Datetime nowDate) {
PPTTrackerBatch batch = new PPTTrackerBatch(nowDate);
Database.executeBatch(batch, 500);
}

global Database.QueryLocator start(Database.BatchableContext BC) {
....}

@future (callout=true)
public static void doCalloutFromFuture() {
//Add code to perform callout
}

global void execute(Database.BatchableContext BC, List<sObject> items) {..
// ЗДЕСЬ ТВОЯ ЛОГИКА ИЛИ FUTURE MЕТОД
doCalloutFromFuture();

..}
}


+ Лучше если ты еще создашь хелпер класс и разнесешь логику и выполнение батча.

Я бы сделал так. Есть какой-то Scheduler (работающий 1 раз в 15 минут)
[code]global class TestScheduler implements Schedulable{
global void execute(SchedulableContext SC) {
      if(!Test.isRunningTest()) {
          MyBatch.startBatch(DateTime.now());
      }
      System.abortJob(sc.getTriggerId());
      run(DateTime.now());
   }
}
public static void run(DateTime nextDate) {
       String cronString = '0 ' +  nextDate.addMinutes(15) + ' * * * ?'';
        System.schedule('TestScheduler' + DateTime.now(), cronString, new TestScheduler ());
    }

[/code]

Я бы сделал так. И обрати внимание на MyBatch.startBatch(DateTime.now());  А в батче нечто следующее:

[code]
global class MyBatch implements Database.Batchable<sObject>, Database.Stateful  {

private Datetime startDate4Batch;
	
	global PPTTrackerBatch(Datetime startDate4Batch) {
		this.startDate4Batch = startDate4Batch;
	}

public static void startBatch(Datetime nowDate) {
		PPTTrackerBatch batch  = new PPTTrackerBatch(nowDate);
        Database.executeBatch(batch, 500);
    }

global Database.QueryLocator start(Database.BatchableContext BC) { 
....}

  @future (callout=true)
  public static void doCalloutFromFuture() {
   //Add code to perform callout
}

	global void execute(Database.BatchableContext BC, List<sObject> items) {..
// ЗДЕСЬ ТВОЯ ЛОГИКА ИЛИ FUTURE MЕТОД
doCalloutFromFuture();

..}
}[/code]


+ Лучше если ты еще создашь хелпер класс и разнесешь логику и выполнение батча.

Все еще проще. Не нужны никакие @future

В Scheduler, правильно, только вызов батча и больше ничего.

В start методе батча - подготовка данных для выполнения батча, в том числе необходимые для инициализации callouts.

В execute методе остальные callouts, для синхронизации пачками. Ошибки (exceptions) складываем в отдельный объект типа log

В финиш обработка ошибок.

Вот и весь план. У меня по такому принципе уже не одна синхронизация работает, очень даже успешно.

"Ошибки (exceptions) складываем в отдельный объект типа log" - это особенно полезно, если у тебя будет страница для отслеживания статуса синхронизации - просто периодически выводишь последние ошибки и лога. Получается такая асинхронная работа.

Все еще проще. Не нужны никакие @future

В Scheduler, правильно, только вызов батча и больше ничего.

В start методе батча - подготовка данных для выполнения батча, в том числе необходимые для инициализации callouts.

В execute методе остальные callouts, для синхронизации пачками. Ошибки (exceptions) складываем в отдельный объект типа log

В финиш обработка ошибок.

Вот и весь план. У меня по такому принципе уже не одна синхронизация работает, очень даже успешно.

"Ошибки (exceptions) складываем в отдельный объект типа log" - это особенно полезно, если у тебя будет страница для отслеживания статуса синхронизации - просто периодически выводишь последние ошибки и лога. Получается такая асинхронная работа.

Ухти <!-- s:P --><img src="{SMILIES_PATH}/icon_razz.gif" alt=":P" title="Дразнится" /><!-- s:P --> , спасибо огромное Artem Levchenko.

Да, Dmitry Shnyrev, без future мне больше нравится.

А можете обяснить неопытному, что означает Database.Stateful в Батче.

Database.executeBatch(batch, 500);

В етом случае размер батча всьо равно останется 200, или я чегото непонимаю?

И можете обяснить предназначение startDate4Batch?

Ухти <!-- s:P --><img src="{SMILIES_PATH}/icon_razz.gif" alt=":P" title="Дразнится" /><!-- s:P --> , спасибо огромное Artem Levchenko. 

Да, Dmitry Shnyrev, без future мне больше нравится. 

А можете обяснить неопытному, что означает Database.Stateful в Батче. 

[quote]Database.executeBatch(batch, 500);[/quote]
В етом случае размер батча всьо равно останется 200, или я чегото непонимаю?

И можете обяснить предназначение startDate4Batch?

Если батч используется для очереди сложных операций (например синхронизации пачками),
то метод execute подразумевается использовать как отдельный логический блок кода, поэтому подготавливать данные и запускать его надо так:

Database.executeBatch(batch, 1);

Если батч используется для очереди сложных операций (например синхронизации пачками),
то метод execute подразумевается использовать как отдельный логический блок кода, поэтому подготавливать данные и запускать его надо так:
[code]
Database.executeBatch(batch, 1);
[/code]

Ты можешь, если тебе в Batch нужно callout по веб-сервису... то можно добавить поддержку
Using Callouts in Batch Apex
To use a callout in batch Apex, you must specify Database.AllowsCallouts in the class definition. For example:

global class SearchAndReplace implements Database.Batchable<sObject>, 
Database.AllowsCallouts{
}
.

Callouts include HTTP requests as well as methods defined with the webService keyword

http://www.salesforce.com/us/developer/docs/apexcode/Content/apex_batch_interface.htm

А можете обяснить неопытному, что означает Database.Stateful в Батче.

Ты можешь сохранять состояние между выполнениями партий. Т.е если у тебя по 10 записей обрабатывается. А всего 100. То будет 10 транзакций. А если тебе, например, для 100 записей нужно что-нить проагрегировать? Если ты не укажешь Database.Statefull в батче, то ты не сможешь отследить состояние записей, над которыми уже были проведены манипуляции в батче. А вообще смотри документ:

http://www.salesforce.com/us/developer/docs/apexcode/Content/apex_batch_interface.htm

Все отлично описано) Успехов

Ты можешь, если тебе в Batch нужно callout по веб-сервису... то можно добавить поддержку
Using Callouts in Batch Apex
To use a callout in batch Apex, you must specify Database.AllowsCallouts in the class definition. For example:
[code]
global class SearchAndReplace implements Database.Batchable<sObject>, 
   Database.AllowsCallouts{
}
.[/code]
Callouts include HTTP requests as well as methods defined with the webService keyword

[url]http://www.salesforce.com/us/developer/docs/apexcode/Content/apex_batch_interface.htm[/url]

[quote] А можете обяснить неопытному, что означает Database.Stateful в Батче. [/quote]
Ты можешь сохранять состояние между выполнениями партий. Т.е если у тебя по 10 записей обрабатывается. А всего 100. То будет 10 транзакций. А если тебе, например, для 100 записей нужно что-нить проагрегировать? Если ты не укажешь Database.Statefull в батче, то ты не сможешь отследить состояние записей, над которыми уже были проведены манипуляции в батче. А вообще смотри документ:

[url]http://www.salesforce.com/us/developer/docs/apexcode/Content/apex_batch_interface.htm[/url]

Все отлично описано) Успехов

Дима здесь высказывал опасения что батч может запуститься два раза,да может,но есть специальный код который проверяет есть ли твой bacth на данный момент на выполнении,если нет тогда можно запускать еще в один экземпляр batch.

Дима здесь высказывал опасения что батч может запуститься два раза,да может,но есть специальный код который проверяет есть ли твой bacth на данный момент на выполнении,если нет тогда можно запускать еще в один экземпляр batch.

Сергей, а что за "специальный код"? Предлагаю обсудить.

Сергей, а что за "специальный код"? Предлагаю обсудить.

Уж не про это вы имеете в виду?

[Select ApexClassID FROM AsyncApexJob WHERE JobType='BatchApex' AND(Status = 'Processing' OR Status = 'Preparing')];

Уж не про это вы имеете в виду?
[code]
[Select ApexClassID FROM AsyncApexJob WHERE JobType='BatchApex' AND(Status = 'Processing' OR Status = 'Preparing')];
 [/code]

Art Vegas
Уж не про это вы имеете в виду?
[Select ApexClassID FROM AsyncApexJob WHERE JobType='BatchApex' AND(Status = 'Processing' OR Status = 'Preparing')];

Да очень очень похоже правда не множко другое было Where ну суть таже.

[quote="Art Vegas"]Уж не про это вы имеете в виду?
[code]
[Select ApexClassID FROM AsyncApexJob WHERE JobType='BatchApex' AND(Status = 'Processing' OR Status = 'Preparing')];
 [/code][/quote]
Да очень очень похоже :D правда не множко другое было Where ну суть таже.