बैच अनुरोध भेजें

इस दस्तावेज़ में बताया गया है कि क्लाइंट को कम कनेक्शन बनाने के लिए, एपीआई कॉल को एक साथ कैसे बैच किया जा सकता है.

इस दस्तावेज़ में खास तौर पर, Java क्लाइंट लाइब्रेरी का इस्तेमाल करके बैच रिक्वेस्ट करने के बारे में बताया गया है. एक बुनियादी उदाहरण .NET के लिए Google API क्लाइंट लाइब्रेरी. Google Play EMM API का बैच सिस्टम एक ही एचटीटीपी का इस्तेमाल करता है OData बैच प्रोसेसिंग सिस्टम के तौर पर सिंटैक्स का इस्तेमाल किया जाता है.

खास जानकारी

Google Play के ईएमएम एपीआई की मदद से, आपका क्लाइंट जो भी अनुरोध करता है उसकी एक तय रकम होती है. Google Play का ईएमएम एपीआई एक साथ कई ईमेल भेजने की सुविधा देता है. इससे आपका क्लाइंट एक ही अनुरोध में कई एपीआई कॉल शामिल कर सकता है.

यहां उन स्थितियों के कुछ उदाहरण दिए गए हैं जिनमें एक साथ कई बैच बनाने की सुविधा इस्तेमाल की जा सकती है:

  • एक डोमेन को अभी-अभी रजिस्टर किया गया है और अब इसमें अपलोड करने के लिए बहुत सारा डेटा है.
  • आपके ऐप्लिकेशन के ऑफ़लाइन होने पर किसी उपयोगकर्ता ने डेटा में बदलाव किए थे, इसलिए आपके ऐप्लिकेशन को सर्वर के साथ बहुत ज़्यादा स्थानीय डेटा सिंक करने की ज़रूरत है.

ऐसे मामलों में, हर कॉल को अलग से भेजने के बजाय, उन्हें एक ही अनुरोध में ग्रुप किया जा सकता है. यहां तक कि आप एक से ज़्यादा उपयोगकर्ताओं या एक से ज़्यादा Google API के लिए ग्रुप अनुरोधों को भी भेज सकते हैं.

हालांकि, एक बैच में ज़्यादा से ज़्यादा 1, 000 कॉल किए जा सकते हैं. अगर आपको इससे ज़्यादा कॉल करने हैं, तो एक से ज़्यादा बैच रिक्वेस्ट का इस्तेमाल करें.

बैच की जानकारी

एक साथ कई एपीआई कॉल करने के अनुरोध में, एक JSON-RPC अनुरोध में कई एपीआई कॉल शामिल होते हैं. इस सेक्शन में, बैच रिक्वेस्ट सिंटैक्स के बारे में पूरी जानकारी दी गई है. इसका उदाहरण नीचे दिए गए सेक्शन में दिया गया है.

ध्यान दें: एक साथ बैच में किए गए n अनुरोधों को एक अनुरोध के तौर पर नहीं, बल्कि इस्तेमाल की सीमा n में गिना जाता है. प्रोसेस करने से पहले, एक साथ कई अनुरोधों को अलग-अलग सेट में ले जाया जाता है.

बैच रिक्वेस्ट का फ़ॉर्मैट

Java क्लाइंट लाइब्रेरी में, हर Google Play ईएमएम एपीआई कॉल के लिए अनुरोध बनाने के लिए कॉल शामिल होते हैं. उदाहरण के लिए, किसी डिवाइस पर इंस्टॉल किए गए सभी ऐप्लिकेशन की सूची बनाने के लिए, आपको इन चीज़ों का इस्तेमाल करना होगा:

AndroidEnterprise enterprise = ...;
InstallsListResponse response = enterprise.installs().list(enterpriseId, userId, deviceId)
  .execute();

एक और batch() कॉल की वजह से कई अनुरोध सूची में जुड़ सकते हैं, जैसा कि यहां दिखाया गया है:

AndroidEnterprise enterprise = ...;
BatchRequest batchRequest = enterprise.batch();
enterprise.installs().list(enterpriseId, userId, deviceId1).queue(batchRequest, callback1);
enterprise.installs().list(enterpriseId, userId, deviceId2).queue(batchRequest, callback2);
enterprise.installs().list(enterpriseId, userId, deviceId3).queue(batchRequest, callback3);
batchRequest.execute();
अभी तक किसी भी व्यक्ति ने चेक इन नहीं किया है batchRequest.execute() को कॉल करने पर, सूची में मौजूद सभी अनुरोध एक साथ सर्वर पर, JSON फ़ॉर्मैट में भेजे जाते हैं. सर्वर, आउटर अनुरोध के क्वेरी पैरामीटर और हेडर (ज़रूरत के हिसाब से) को हर हिस्से पर लागू करता है. इसके बाद, हर हिस्से को इस तरह देखता है मानो कि यह कोई अलग JSON अनुरोध हो.

बैच में भेजे गए अनुरोध का जवाब

सर्वर हर अनुरोध को लागू करता है और नतीजों को सिंगल अरे से बने सिंगल रिस्पॉन्स में ग्रुप करता है. क्लाइंट लाइब्रेरी इस जवाब को अलग-अलग जवाबों में बांटती है और हर जवाब queue() को पास किए गए कॉलबैक फ़ंक्शन पर भेजा जाता है. कॉलबैक एक ऐसा इंटरफ़ेस है जो फ़ेल हो जाने और सफलता पाने का तरीका बताता है. उदाहरण के लिए, callback1 को यहां दी गई स्थितियों के तौर पर लागू किया जाएगा:

private class InstallsCallback implements JsonBatchCallback<InstallsListResponse> {

  @Override
  public void onSuccess(InstallsListResponse response, HttpHeaders responseHeaders) {
    ...
  }

  @Override
  public void onFailure(GoogleJsonError e, HttpHeaders responseHeaders) {
    ...
  }
}

ध्यान दें: सर्वर आपके कॉल किसी भी क्रम में कर सकता है. इसलिए, अपने अनुरोध में बताए गए ऑर्डर के नतीजों पर भरोसा न करें. अगर आपको यह पक्का करना है कि दो कॉल किसी दिए गए क्रम में हों, तो उन्हें एक ही अनुरोध में नहीं भेजा जा सकता; इसके बजाय, पहला अनुरोध खुद ही भेजें और दूसरा अनुरोध भेजने से पहले, उसके जवाब का इंतज़ार करें.

एक साथ कई अनुरोध करने का उदाहरण

नीचे दिया गया उदाहरण किसी उपयोगकर्ता के सभी डिवाइस पर इंस्टॉल किए गए सभी ऐप्लिकेशन की सूची बनाने का तरीका बताता है. पहले कॉल का इस्तेमाल एंटरप्राइज़ और उपयोगकर्ता के आईडी को पाने के लिए किया जाता है और उसी हिसाब से उन्हें एक क्रम में कॉल किया जाना चाहिए. enterprise.devices().list() से सभी डिवाइस आईडी मिल जाने के बाद, हम उपयोगकर्ता के सभी डिवाइसों पर मौजूद सभी ऐप्लिकेशन को एक साथ वापस पाने के लिए, बैच में अनुरोध कर सकते हैं.

package com.google.playenterprise.example;

import com.google.api.client.auth.oauth2.Credential;
import com.google.api.client.googleapis.auth.oauth2.GoogleCredential;
import com.google.api.client.googleapis.batch.BatchRequest;
import com.google.api.client.googleapis.batch.json.JsonBatchCallback;
import com.google.api.client.googleapis.json.GoogleJsonError;
import com.google.api.client.http.HttpHeaders;
import com.google.api.client.http.HttpRequest;
import com.google.api.client.http.HttpRequestInitializer;
import com.google.api.client.http.HttpTransport;
import com.google.api.client.http.javanet.NetHttpTransport;
import com.google.api.client.json.JsonFactory;
import com.google.api.client.json.jackson.JacksonFactory;
import com.google.api.services.androidenterprise.AndroidEnterprise;
import com.google.api.services.androidenterprise.AndroidEnterprise.Installs;
import com.google.api.services.androidenterprise.AndroidEnterpriseScopes;
import com.google.api.services.androidenterprise.model.Device;
import com.google.api.services.androidenterprise.model.DevicesListResponse;
import com.google.api.services.androidenterprise.model.Enterprise;
import com.google.api.services.androidenterprise.model.Install;
import com.google.api.services.androidenterprise.model.InstallsListResponse;

import java.io.BufferedInputStream;
import java.io.FileInputStream;
import java.io.IOException;
import java.io.InputStream;
import java.util.ArrayList;
import java.util.List;

/**
 * Lists all the apps installed on all devices of a given user.
 */
public class ListAllInstalls {
  private AndroidEnterprise enterprise;
  private final List<String> installList = new ArrayList<>();

  public static void main(String[] argv) throws Exception {
    if (argv.length != 2) {
      throw new IllegalArgumentException("Usage: ListAllInstalls email jsonFilename");
    } else if (!argv[0].contains("@")) {
      throw new IllegalArgumentException("First parameter should be a valid email.");
    }
    new ListAllInstalls().run(argv[0], argv[1]);
  }

  private void run(String userEmail, String jsonKeyPath) throws IOException {
    enterprise = createAndroidEnterprise(jsonKeyPath);

    // Get the enterprise id, user id, and user devices.
    String domain = userEmail.split("@")[1];
    List<Enterprise> results = enterprise.enterprises().list(domain).execute().getEnterprise();
    if (results.isEmpty()) {
      throw new RuntimeException("No enterprise found.");
    }
    String enterpriseId = results.get(0).getId();
    String userId = enterprise
        .users()
        .list(enterpriseId, userEmail)
        .execute()
        .getUser()
        .get(0)
        .getId();
    List<Device> devices = getAllDevices(enterpriseId, userId);

    // Batch all calls to get installs on all user devices.
    gatherAllInstalls(enterpriseId, userId, devices);

    for (String entry : installList) {
      // Do something.
      System.out.println(entry);
    }
  }

  private List<Device> getAllDevices(String enterpriseId, String userId) throws IOException {
    DevicesListResponse devices = enterprise.devices().list(enterpriseId, userId).execute();
    return devices.getDevice();
  }

  private void gatherAllInstalls(String enterpriseId, String userId, List<Device> devices)
      throws IOException {
    BatchRequest batchRequest = enterprise.batch();
    for (Device device : devices) {
      Installs.List list = enterprise
          .installs().list(enterpriseId, userId, device.getAndroidId());
      // Each callback can take the specifics of the associated request in its constructor.
      list.queue(batchRequest, new InstallsCallback(device.getAndroidId()));
    }
    // Executes all the queued requests and their callbacks, single-threaded.
    batchRequest.execute();
  }

  private class InstallsCallback extends JsonBatchCallback<InstallsListResponse> {
    private final String androidId;

    InstallsCallback(String androidId) {
      this.androidId = androidId;
    }

    @Override
    public void onSuccess(InstallsListResponse response, HttpHeaders responseHeaders) {
      for (Install install : response.getInstall()) {
        installList.add(androidId + "," + install.getProductId());
      }
    }

    @Override
    public void onFailure(GoogleJsonError e, HttpHeaders responseHeaders) {
      throw new RuntimeException("Error fetching a device");
    }
  }

  private AndroidEnterprise createAndroidEnterprise(String jsonKeyPath) throws IOException {
    HttpTransport httpTransport = new NetHttpTransport();
    JsonFactory jsonFactory = new JacksonFactory();

    InputStream is = new BufferedInputStream(new FileInputStream(jsonKeyPath));
    final Credential credential = GoogleCredential.fromStream(is, httpTransport, jsonFactory)
        .createScoped(AndroidEnterpriseScopes.all());

    HttpRequestInitializer httpRequestInitializer = new HttpRequestInitializer() {
      @Override
      public void initialize(HttpRequest request) throws IOException {
        credential.initialize(request);
      }
    };
    return new AndroidEnterprise.Builder(httpTransport, jsonFactory, httpRequestInitializer)
        .build();
  }
}