Note: This release is in preview. Features described here don’t become generally available until the latest general availability date that Salesforce announces for this release. Before then, and where features are noted as beta, pilot, or developer preview, we can’t guarantee general availability within any particular time frame or at all. Make your purchase decisions only on the basis of generally available products and features.
PackageSubscriber
One record is created per installation. For example, if 5 orgs installed 2 packages, 10 records are created.
Supported Calls
describeSObjects(), query(), retrieve()
Special Access Rules
To initiate a push upgrade for a first-generation managed package, the Upload AppExchange Packages user permission is required.
To initiate a push upgrade for an unlocked or second-generation managed package, the Create and Update Second-Generation Packages user permission is required.
The push upgrade feature is only available to first- and second-generation managed packages that have passed AppExchange security review. To enable push upgrades for your managed package, log a support case in the Salesforce Partner Community.
For unlocked packages, push upgrades are enabled by default.
Fields
| Field Name | Details |
|---|---|
| CustomUpgradeType |
|
| HasRestrictionEnabled |
|
| InstalledStatus |
|
| InstanceName |
|
| IsCustomUpgradeAllowed |
|
| MetadataPackageId |
|
| MetadataPackageVersionId |
|
| OrgKey |
|
| OrgName |
|
| OrgStatus |
|
| OrgType |
|
| ParentOrg |
|
Usage
| Query | String |
|---|---|
| Get all package subscriber orgs with a specific package ID | SELECT Id, OrgKey, OrgStatus, OrgName, OrgType FROM PackageSubscriber WHERE MetadataPackageVersionId = '04t...' |
| Get all package subscriber orgs that have an installed package created by the org you’re logged in to | SELECT Id, OrgKey, OrgStatus, OrgName, OrgType FROM PackageSubscriber WHERE InstalledStatus = 'i' |
Filter PackageSubscriber Objects by Instance
If you have packages with many subscribers, querying PackageSubscriber objects can take a while. To improve query performance, add filters to your PackageSubscriber queries, such as an InstanceName filter. InstanceName is a field that represents the instance that the subscriber org is hosted on.
- Get the org’s package and the latest released version of the
package.
1/** 2* Get the MetadataPackage object corresponding to this org's managed package 3*/ 4public MetadataPackage getMetadataPackage() throws ConnectionException { 5 // retrieve the managed package, which won’t have an empty namespace 6 QueryResult result = conn.query("select id from MetadataPackage where namespaceprefix <> ''"); 7 8 return (MetadataPackage) result.getRecords()[0]; 9} 10 11/** 12* Get the latest MetadataPackageVersion object of the given MetadataPackage 13*/ 14public MetadataPackageVersion getLatestMetadataPackageVersion(MetadataPackage metadataPackage) 15throws ConnectionException { 16 // get the latest released version of the given package 17 String query = "Select id, ReleaseState, MajorVersion, MinorVersion, PatchVersion, 18MetadataPackageId" 19 + " From MetadataPackageVersion" 20 + " Where MetadataPackageId = '%s' and ReleaseState = 'Released'" 21 + " Order by majorversion desc, minorversion desc, patchversion desc"; 22 23 QueryResult result = conn.query(String.format(query, metadataPackage.getId())); 24 25 return (MetadataPackageVersion) result.getRecords()[0]; 26} - Get eligible subscribers. The following query strings and methods are modified
to allow querying for PackageSubscribers filtered by an
instance.
1static final String PACKAGE_SUBSCRIBER_ORG_KEY_QUERY = "Select OrgKey from PackageSubscribers where OrgStatus = 'Active'" 2 + " and InstalledStatus = 'I'" 3 + " and InstanceName = '%s'"; // placeholder for instance values 4 5static final String METADATA_PACKAGE_VERSION_QUERY = "Select Id, Name, ReleaseState, (%s) from MetadataPackageVersion" 6 + " where MetadataPackageId = '%s' AND ReleaseState = 'Released'" 7 + " AND (MajorVersion < %s OR (MajorVersion = %s and MinorVersion < %s)" 8 + " OR (MajorVersion = %s and MinorVersion = %s and PatchVersion < %s))"; 9 10/** 11* Get all PackageSubscribers on the given instance that are eligible to upgrade to the given 12* MetadataPackageVersion 13*/ 14public PackageSubscriber[] getEligibleSubscriberIds(MetadataPackageVersion version, String instanceName) throws ConnectionException { 15 String allPackageId = version.getMetadataPackageId(); 16 Integer major = version.getMajorVersion(); 17 Integer minor = version.getMinorVersion(); 18 Integer patch = version.getPatchVersion(); 19 20 return getEligibleSubscriberIds(major, minor, patch, allPackageId, instanceName); 21}1public PackageSubscriber[] getEligibleSubscriberIds(Integer major, Integer minor, Integer patch, String packageId, String instanceName) throws ConnectionException { 2 String subscriberQuery = String.format(PACKAGE_SUBSCRIBER_ORG_KEY_QUERY, instanceName); 3QueryResult results = conn.query(String.format(METADATA_PACKAGE_VERSION_QUERY, 4subscriberQuery, packageId, major, major, minor, major, minor, patch)); 5 6 return Arrays.stream(results.getRecords()).map(MetadataPackageVersion.class::cast) 7 .filter(mpv -> mpv.getPackageSubscribers() != null) 8 .flatMap(mpv -> Arrays.stream(mpv.getPackageSubscribers().getRecords())) 9 .map(PackageSubscriber.class::cast) 10 .toArray(PackageSubscriber[]::new); 11} - Put it all together. The following code sample shows how to use the previous
methods to modify the workflow to perform package pushes by
instance.
1String[] instances = { "NA4" }; // Here we list the instances we would like to push to 2MetadataPackage metadataPackage = api.getMetadataPackage(); 3MetadataPackageVersion version = api.getLatestMetadataPackageVersion(metadataPackage); 4 5// do pushes by instance to avoid API timeouts retrieving PackageSubscribers 6for (String instanceName : instances) { 7PackageSubscriber[] eligibleSubscribers = api.getEligibleSubscriberIds(version, 8instanceName); 9 10// ... proceed with creating PushRequests and PushJobs as before