Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

[match] add caching layer to significantly improve performance by up to 100x #21694

Merged
merged 16 commits into from Dec 14, 2023

Conversation

nekrich
Copy link
Contributor

@nekrich nekrich commented Dec 4, 2023

Checklist

  • I've run bundle exec rspec from the root directory to see all new and existing tests pass
  • I've followed the fastlane code style and run bundle exec rubocop -a to ensure the code style is valid
  • I see several green ci/circleci builds in the "All checks have passed" section of my PR (connect CircleCI to GitHub if not)
  • I've read the Contribution Guidelines
  • I've updated the documentation if necessary.
  • I've added or updated relevant unit tests.

Hi.

Problem

We have 112 provisioning profiles. And running match not in readonly mode takes a lot of time for us.
I've made a Faraday middleware to count requests, fetch time, and the amount of passed data.
I saw many redundant fetches: profiles, certificates, bundle IDs, and devices fetched for each app_identifier and some of them several times.

tl;dr; The cached version of the match installs all 112 profiles with cert and device checks as fast as the current version manages to check and install just one development profile with the same parameters.

Description

Introduce cache and fetcher for match. We must save the state of profiles, certificates, bundle IDs, and devices. I've looked at what information changes when the match is executed and what is static.

  • Bundle IDs: static. match doesn't modify bundle identifiers.
  • Devices: static. match doesn't modify devices.
  • Provisioning: static. match just checks if the current provisioning is valid. After generating a new one, we don't need to update or reset the cache with a new provisioning profile because it's unused for the next app_identifier.
  • Certificates: dynamic but close to static. When the match generates a new certificate, it generates it only once for all app_identifiers, and resetting the cache once is not a big problem.
    With this, I see that caching will not bring a lot of headaches, and there will be no cache inconsistency. And introducing cache on the instance level will probably bring more good than bad.

Another good thing is that the match is executed with strict parameters: type and platform. And we can write better filters for fetching certificates and profiles.

Results (x100 😅)

Before After %
calls count 1,894 21 0.011
duration in seconds 4,957.58 30.57 0.006
response size 2,702,427,979 16,945,609 0.006

Stats per url

Before:

{
  "https://api.appstoreconnect.apple.com/v1/bundleIds": {
    "duration": 85.95213599999997,
    "size": 285596,
    "calls_count": 112
  },
  "https://api.appstoreconnect.apple.com/v1/certificates": {
    "duration": 282.9322100000001,
    "size": 12128325,
    "calls_count": 244
  },
  "https://api.appstoreconnect.apple.com/v1/profiles": {
    "duration": 4370.683801999995,
    "size": 2687726458,
    "calls_count": 1258
  },
  "https://api.appstoreconnect.apple.com/v1/devices": {
    "duration": 218.01276800000005,
    "size": 2287600,
    "calls_count": 280
  }
}

After:

{
  "https://api.appstoreconnect.apple.com/v1/bundleIds": {
    "duration": 9.408271000000001,
    "size": 199607,
    "calls_count": 9
  },
  "https://api.appstoreconnect.apple.com/v1/certificates": {
    "duration": 5.092039,
    "size": 378884,
    "calls_count": 5
  },
  "https://api.appstoreconnect.apple.com/v1/profiles": {
    "duration": 14.223327999999999,
    "size": 16328383,
    "calls_count": 5
  },
  "https://api.appstoreconnect.apple.com/v1/devices": {
    "duration": 1.850342,
    "size": 38735,
    "calls_count": 2
  }
}

Solution

This PR.

To ease the review, I can split it into 5 smaller PRs:

  1. Move device_count_different? and certificate_count_different? to a new file.
  2. Slightly refactor sigh: move profile_type and certificate_types map functions to a module.
  3. Create a Match::Portal::Fetcher to have a controlled entry point for API requests.
  4. Add Match::Portal::Cache.
  5. Inject cached data into the sigh when creating profiles.

As for me, making separate PRs into the main branch makes almost no sense. I'm a fan of a feature branch but not a maintainer 😅. If you are ready for one biggie, please let me know.

Please tell me if my solution can be merged into the fastlane, and what strategy of PRs you would like to use.

PS. I want to thank @PaulTaykalo for his #21016 PR, which I included in this one. Paul, I hope you don't mind 😉.

@lacostej
Copy link
Collaborator

lacostej commented Dec 4, 2023

Thanks @nekrich. Nice PR here. I don't mind the large PR. Will look into this during the week.

@nekrich nekrich force-pushed the feat/match-speed branch 3 times, most recently from 7d19210 to d8ae5a4 Compare December 5, 2023 12:52
@nekrich nekrich changed the title [wip] [match] caching [wip] [match] increase match speed with caching Dec 5, 2023
@nekrich nekrich changed the title [wip] [match] increase match speed with caching [match] increase match speed with caching Dec 5, 2023
@nekrich nekrich marked this pull request as ready for review December 5, 2023 16:43
Copy link
Collaborator

@lacostej lacostej left a comment

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

First pass. One major comment regarding the design, and several nitpicks.

The code is really clean, appreciated 👍.

sigh/lib/sigh/options.rb Outdated Show resolved Hide resolved
match/spec/spec_helper.rb Outdated Show resolved Hide resolved
match/lib/match/portal_fetcher.rb Outdated Show resolved Hide resolved
match/lib/match/portal_fetcher.rb Outdated Show resolved Hide resolved
match/lib/match/module.rb Show resolved Hide resolved
match/lib/match/runner.rb Outdated Show resolved Hide resolved
sigh/lib/sigh/runner.rb Outdated Show resolved Hide resolved
match/lib/match/profile_includes.rb Outdated Show resolved Hide resolved
match/lib/match/runner.rb Outdated Show resolved Hide resolved
match/lib/match/spaceship_ensure.rb Show resolved Hide resolved
@nekrich nekrich requested a review from lacostej December 6, 2023 17:26
Copy link
Member

@rogerluan rogerluan left a comment

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

This PR is awesome! I only did a partial review so far though 🙏 but the improvements you've observed are game-changing, thanks for this!!

I didn't have the time to go through the entire PR atm, but I have a few questions:

  1. Is the cache persistent (e.g. on disk)? If so, what's the persistency scope (e.g. is it valid throughout different fastlane action calls of a single lane, or different fastlane lane calls?
  2. What is the cache bursting logic?

Again thanks for all the effort you put in this PR, I'm glad it solved the performance issues you had and excited for other people to be able to access this! 🙌

match/spec/portal_fetcher_spec.rb Outdated Show resolved Hide resolved
match/spec/portal_fetcher_spec.rb Show resolved Hide resolved
match/lib/match/module.rb Show resolved Hide resolved
@rogerluan rogerluan changed the title [match] increase match speed with caching [match] add caching layer to significantly improve performance by up to 100x Dec 12, 2023
Co-authored-by: Roger Oba <rogerluan.oba@gmail.com>
@nekrich
Copy link
Contributor Author

nekrich commented Dec 12, 2023

@rogerluan ,

  1. Is the cache persistent (e.g. on disk)? If so, what's the persistency scope (e.g. is it valid throughout different fastlane action calls of a single lane, or different fastlane lane calls?
  2. What is the cache bursting logic?
  1. It's in-memory cache.

  2. It works only in match. match action is responsible for its own cache.

  3. There is an option to pass cached objects to the sigh from match.

  4. Cache lifetime is a single match run.
    It has two internal invalidation points:

    • The whole certificates cache is reset on cert generation.
    • "Forgetting" a single provision after a new one was created. Which now is redundant after fixing a @lacostej comment.

    No long-term persistence lane or a whole fastlane run. And no headache on what to do if the lane runs 30 mins, and we have another Fastlane run on another computer which made changes to certs/profiles.

    It doesn't fetch irrelevant info and utilizes available filters in the API — filter cert by types, fetch only active devices, only listed bundle ids.

Copy link
Member

@rogerluan rogerluan left a comment

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

🚀

@lacostej
Copy link
Collaborator

🚀! Nice PR @nekrich. Thanks @milch @rogerluan :)

@lacostej lacostej merged commit a3715d6 into fastlane:master Dec 14, 2023
2 checks passed
@thanhcuong1990
Copy link

@nekrich I'm experiencing an issue with the error message "cached_profiles parameter must be a non-empty array of Spaceship::ConnectAPI::Profile" after upgrading to fastlane version 2.218.0. I had to revert to version 2.217.0 to resolve the issue.
Any suggestions on how to fix it?

@nekrich
Copy link
Contributor Author

nekrich commented Jan 3, 2024

@nekrich I'm experiencing an issue with the error message "cached_profiles parameter must be a non-empty array of Spaceship::ConnectAPI::Profile" after upgrading to fastlane version 2.218.0. I had to revert to version 2.217.0 to resolve the issue.

Any suggestions on how to fix it?

@thanhcuong1990 , I'll look into in in a couple of hours. Can you please tell what auth type you use: Keys or login and password?

@thanhcuong1990
Copy link

@thanhcuong1990 , I'll look into in in a couple of hours. Can you please tell what auth type you use: Keys or login and password?

I used FASTLANE_APPLE_APPLICATION_SPECIFIC_PASSWORD for auth.

@viktor-savchik-idf
Copy link

The same issue. I'm using *.p8 key

[11:57:22]: Error setting value '[]' for option 'cached_profiles'
+-----------------------------------------+
|              Lane Context               |
+------------------+----------------------+
| DEFAULT_PLATFORM | ios                  |
| PLATFORM_NAME    | ios                  |
| LANE_NAME        | ios certificates_dev |
+------------------+----------------------+
[11:57:22]: cached_profiles parameter must be a non-empty array of Spaceship::ConnectAPI::Profile

+---------------------------------------------------------------------------+
|                             fastlane summary                              |
+------+------------------------------------------------------+-------------+
| Step | Action                                               | Time (in s) |
+------+------------------------------------------------------+-------------+
| 1    | default_platform                                     | 0           |
| 2    | Switch to ios app_store_connect_api_key_creator lane | 0           |
| 3    | app_store_connect_api_key                            | 0           |
| 4    | register_devices                                     | 1           |
| 💥   | match                                                | 9           |
+------+------------------------------------------------------+-------------+

+-----------------------------------------------------------+
|                 Plugin updates available                  |
+---------------------------+--------------+----------------+
| Plugin                    | Your Version | Latest Version |
+---------------------------+--------------+----------------+
| firebase_app_distribution | 0.7.4        | 0.8.0          |
+---------------------------+--------------+----------------+
[11:57:22]: To update all plugins, just run
[11:57:22]: $ bundle exec fastlane update_plugins

[11:57:22]: fastlane finished with errors

[!] cached_profiles parameter must be a non-empty array of Spaceship::ConnectAPI::Profile
 ✘ viktor_savchik@onexoer  ~/path/to/project/ios   master  bundle install

@nekrich
Copy link
Contributor Author

nekrich commented Jan 3, 2024

@viktor-savchik-idf , @thanhcuong1990 can you please check if the fix works nekrich:fix/sigh-cache-parameters-validation?

Gemfile:
gem 'fastlane', :git => 'https://github.com/nekrich/fastlane.git', :branch => 'fix/sigh-cache-parameters-validation')?

@viktor-savchik-idf
Copy link

@nekrich yes, it works

@viktor-savchik-idf
Copy link

viktor-savchik-idf commented Jan 3, 2024

@nekrich but when repeating the same command, there is another issue.

12:59:12  bundler: failed to load command: fastlane (/Users/jenkins/.rbenv/versions/3.1.2/lib/ruby/gems/3.1.0/bin/fastlane)
12:59:12  /Users/jenkins/.rbenv/versions/3.1.2/lib/ruby/gems/3.1.0/bundler/gems/fastlane-729fb915082d/match/lib/match/profile_includes.rb:54:in `devices_differ?': \e[31m[!] undefined method `map' for nil:NilClass (NoMethodError)
12:59:12  
12:59:12        profile_device_ids = profile_devices.map(&:id).sort
12:59:12                                            ^^^^\e[0m
12:59:12  	from /Users/jenkins/.rbenv/versions/3.1.2/lib/ruby/gems/3.1.0/bundler/gems/fastlane-729fb915082d/match/lib/match/profile_includes.rb:23:in `should_force_include_all_devices?'
12:59:12  	from /Users/jenkins/.rbenv/versions/3.1.2/lib/ruby/gems/3.1.0/bundler/gems/fastlane-729fb915082d/match/lib/match/runner.rb:253:in `fetch_provisioning_profile'
12:59:12  	from /Users/jenkins/.rbenv/versions/3.1.2/lib/ruby/gems/3.1.0/bundler/gems/fastlane-729fb915082d/match/lib/match/runner.rb:106:in `block (2 levels) in run'
12:59:12  	from /Users/jenkins/.rbenv/versions/3.1.2/lib/ruby/gems/3.1.0/bundler/gems/fastlane-729fb915082d/match/lib/match/runner.rb:105:in `loop'
12:59:12  	from /Users/jenkins/.rbenv/versions/3.1.2/lib/ruby/gems/3.1.0/bundler/gems/fastlane-729fb915082d/match/lib/match/runner.rb:105:in `block in run'
12:59:12  	from /Users/jenkins/.rbenv/versions/3.1.2/lib/ruby/gems/3.1.0/bundler/gems/fastlane-729fb915082d/match/lib/match/runner.rb:104:in `each'
12:59:12  	from /Users/jenkins/.rbenv/versions/3.1.2/lib/ruby/gems/3.1.0/bundler/gems/fastlane-729fb915082d/match/lib/match/runner.rb:104:in `run'
12:59:12  	from /Users/jenkins/.rbenv/versions/3.1.2/lib/ruby/gems/3.1.0/bundler/gems/fastlane-729fb915082d/fastlane/lib/fastlane/actions/sync_code_signing.rb:19:in `run'
12:59:12  	from /Users/jenkins/.rbenv/versions/3.1.2/lib/ruby/gems/3.1.0/bundler/gems/fastlane-729fb915082d/fastlane/lib/fastlane/runner.rb:263:in `block (2 levels) in execute_action'
12:59:12  	from /Users/jenkins/.rbenv/versions/3.1.2/lib/ruby/gems/3.1.0/bundler/gems/fastlane-729fb915082d/fastlane/lib/fastlane/actions/actions_helper.rb:69:in `execute_action'
12:59:12  	from /Users/jenkins/.rbenv/versions/3.1.2/lib/ruby/gems/3.1.0/bundler/gems/fastlane-729fb915082d/fastlane/lib/fastlane/runner.rb:255:in `block in execute_action'
12:59:12  	from /Users/jenkins/.rbenv/versions/3.1.2/lib/ruby/gems/3.1.0/bundler/gems/fastlane-729fb915082d/fastlane/lib/fastlane/runner.rb:229:in `chdir'
12:59:12  	from /Users/jenkins/.rbenv/versions/3.1.2/lib/ruby/gems/3.1.0/bundler/gems/fastlane-729fb915082d/fastlane/lib/fastlane/runner.rb:229:in `execute_action'
12:59:12  	from /Users/jenkins/.rbenv/versions/3.1.2/lib/ruby/gems/3.1.0/bundler/gems/fastlane-729fb915082d/fastlane/lib/fastlane/runner.rb:157:in `trigger_action_by_name'
12:59:12  	from /Users/jenkins/.rbenv/versions/3.1.2/lib/ruby/gems/3.1.0/bundler/gems/fastlane-729fb915082d/fastlane/lib/fastlane/fast_file.rb:159:in `method_missing'
12:59:12  	from Fastfile:40:in `block (2 levels) in parsing_binding'
12:59:12  	from /Users/jenkins/.rbenv/versions/3.1.2/lib/ruby/gems/3.1.0/bundler/gems/fastlane-729fb915082d/fastlane/lib/fastlane/lane.rb:41:in `call'
12:59:12  	from /Users/jenkins/.rbenv/versions/3.1.2/lib/ruby/gems/3.1.0/bundler/gems/fastlane-729fb915082d/fastlane/lib/fastlane/runner.rb:204:in `try_switch_to_lane'
12:59:12  	from /Users/jenkins/.rbenv/versions/3.1.2/lib/ruby/gems/3.1.0/bundler/gems/fastlane-729fb915082d/fastlane/lib/fastlane/runner.rb:146:in `trigger_action_by_name'
12:59:12  	from /Users/jenkins/.rbenv/versions/3.1.2/lib/ruby/gems/3.1.0/bundler/gems/fastlane-729fb915082d/fastlane/lib/fastlane/fast_file.rb:159:in `method_missing'
12:59:12  	from Fastfile:178:in `block (2 levels) in parsing_binding'
12:59:12  	from /Users/jenkins/.rbenv/versions/3.1.2/lib/ruby/gems/3.1.0/bundler/gems/fastlane-729fb915082d/fastlane/lib/fastlane/lane.rb:41:in `call'
12:59:12  	from /Users/jenkins/.rbenv/versions/3.1.2/lib/ruby/gems/3.1.0/bundler/gems/fastlane-729fb915082d/fastlane/lib/fastlane/runner.rb:49:in `block in execute'
12:59:12  	from /Users/jenkins/.rbenv/versions/3.1.2/lib/ruby/gems/3.1.0/bundler/gems/fastlane-729fb915082d/fastlane/lib/fastlane/runner.rb:45:in `chdir'
12:59:12  	from /Users/jenkins/.rbenv/versions/3.1.2/lib/ruby/gems/3.1.0/bundler/gems/fastlane-729fb915082d/fastlane/lib/fastlane/runner.rb:45:in `execute'
12:59:12  	from /Users/jenkins/.rbenv/versions/3.1.2/lib/ruby/gems/3.1.0/bundler/gems/fastlane-729fb915082d/fastlane/lib/fastlane/lane_manager.rb:46:in `cruise_lane'
12:59:12  	from /Users/jenkins/.rbenv/versions/3.1.2/lib/ruby/gems/3.1.0/bundler/gems/fastlane-729fb915082d/fastlane/lib/fastlane/command_line_handler.rb:34:in `handle'
12:59:12  	from /Users/jenkins/.rbenv/versions/3.1.2/lib/ruby/gems/3.1.0/bundler/gems/fastlane-729fb915082d/fastlane/lib/fastlane/commands_generator.rb:110:in `block (2 levels) in run'
12:59:12  	from /Users/jenkins/.rbenv/versions/3.1.2/lib/ruby/gems/3.1.0/gems/commander-4.6.0/lib/commander/command.rb:187:in `call'
12:59:12  	from /Users/jenkins/.rbenv/versions/3.1.2/lib/ruby/gems/3.1.0/gems/commander-4.6.0/lib/commander/command.rb:157:in `run'
12:59:12  	from /Users/jenkins/.rbenv/versions/3.1.2/lib/ruby/gems/3.1.0/gems/commander-4.6.0/lib/commander/runner.rb:444:in `run_active_command'
12:59:12  	from /Users/jenkins/.rbenv/versions/3.1.2/lib/ruby/gems/3.1.0/bundler/gems/fastlane-729fb915082d/fastlane_core/lib/fastlane_core/ui/fastlane_runner.rb:124:in `run!'
12:59:12  	from /Users/jenkins/.rbenv/versions/3.1.2/lib/ruby/gems/3.1.0/gems/commander-4.6.0/lib/commander/delegates.rb:18:in `run!'
12:59:12  	from /Users/jenkins/.rbenv/versions/3.1.2/lib/ruby/gems/3.1.0/bundler/gems/fastlane-729fb915082d/fastlane/lib/fastlane/commands_generator.rb:354:in `run'
12:59:12  	from /Users/jenkins/.rbenv/versions/3.1.2/lib/ruby/gems/3.1.0/bundler/gems/fastlane-729fb915082d/fastlane/lib/fastlane/commands_generator.rb:43:in `start'
12:59:12  	from /Users/jenkins/.rbenv/versions/3.1.2/lib/ruby/gems/3.1.0/bundler/gems/fastlane-729fb915082d/fastlane/lib/fastlane/cli_tools_distributor.rb:123:in `take_off'
12:59:12  	from /Users/jenkins/.rbenv/versions/3.1.2/lib/ruby/gems/3.1.0/bundler/gems/fastlane-729fb915082d/bin/fastlane:23:in `<top (required)>'
12:59:12  	from /Users/jenkins/.rbenv/versions/3.1.2/lib/ruby/gems/3.1.0/bin/fastlane:25:in `load'
12:59:12  	from /Users/jenkins/.rbenv/versions/3.1.2/lib/ruby/gems/3.1.0/bin/fastlane:25:in `<top (required)>'
12:59:12  	from /Users/jenkins/.rbenv/versions/3.1.2/lib/ruby/gems/3.1.0/gems/bundler-2.4.19/lib/bundler/cli/exec.rb:58:in `load'
12:59:12  	from /Users/jenkins/.rbenv/versions/3.1.2/lib/ruby/gems/3.1.0/gems/bundler-2.4.19/lib/bundler/cli/exec.rb:58:in `kernel_load'
12:59:12  	from /Users/jenkins/.rbenv/versions/3.1.2/lib/ruby/gems/3.1.0/gems/bundler-2.4.19/lib/bundler/cli/exec.rb:23:in `run'
12:59:12  	from /Users/jenkins/.rbenv/versions/3.1.2/lib/ruby/gems/3.1.0/gems/bundler-2.4.19/lib/bundler/cli.rb:492:in `exec'
12:59:12  	from /Users/jenkins/.rbenv/versions/3.1.2/lib/ruby/gems/3.1.0/gems/bundler-2.4.19/lib/bundler/vendor/thor/lib/thor/command.rb:27:in `run'
12:59:12  	from /Users/jenkins/.rbenv/versions/3.1.2/lib/ruby/gems/3.1.0/gems/bundler-2.4.19/lib/bundler/vendor/thor/lib/thor/invocation.rb:127:in `invoke_command'
12:59:12  	from /Users/jenkins/.rbenv/versions/3.1.2/lib/ruby/gems/3.1.0/gems/bundler-2.4.19/lib/bundler/vendor/thor/lib/thor.rb:392:in `dispatch'
12:59:12  	from /Users/jenkins/.rbenv/versions/3.1.2/lib/ruby/gems/3.1.0/gems/bundler-2.4.19/lib/bundler/cli.rb:34:in `dispatch'
12:59:12  	from /Users/jenkins/.rbenv/versions/3.1.2/lib/ruby/gems/3.1.0/gems/bundler-2.4.19/lib/bundler/vendor/thor/lib/thor/base.rb:485:in `start'
12:59:12  	from /Users/jenkins/.rbenv/versions/3.1.2/lib/ruby/gems/3.1.0/gems/bundler-2.4.19/lib/bundler/cli.rb:28:in `start'
12:59:12  	from /Users/jenkins/.rbenv/versions/3.1.2/lib/ruby/gems/3.1.0/gems/bundler-2.4.19/exe/bundle:37:in `block in <top (required)>'
12:59:12  	from /Users/jenkins/.rbenv/versions/3.1.2/lib/ruby/gems/3.1.0/gems/bundler-2.4.19/lib/bundler/friendly_errors.rb:117:in `with_friendly_errors'
12:59:12  	from /Users/jenkins/.rbenv/versions/3.1.2/lib/ruby/gems/3.1.0/gems/bundler-2.4.19/exe/bundle:29:in `<top (required)>'
12:59:12  	from /Users/jenkins/.rbenv/versions/3.1.2/bin/bundle:25:in `load'
12:59:12  	from /Users/jenkins/.rbenv/versions/3.1.2/bin/bundle:25:in `<main>'
12:59:12  /Users/jenkins/.rbenv/versions/3.1.2/lib/ruby/gems/3.1.0/bundler/gems/fastlane-729fb915082d/match/lib/match/profile_includes.rb:54:in `devices_differ?': undefined method `map' for nil:NilClass (NoMethodError)
12:59:12  
12:59:12        profile_device_ids = profile_devices.map(&:id).sort
12:59:12                                            ^^^^
12:59:12  	from /Users/jenkins/.rbenv/versions/3.1.2/lib/ruby/gems/3.1.0/bundler/gems/fastlane-729fb915082d/match/lib/match/profile_includes.rb:23:in `should_force_include_all_devices?'
12:59:12  	from /Users/jenkins/.rbenv/versions/3.1.2/lib/ruby/gems/3.1.0/bundler/gems/fastlane-729fb915082d/match/lib/match/runner.rb:253:in `fetch_provisioning_profile'
12:59:12  	from /Users/jenkins/.rbenv/versions/3.1.2/lib/ruby/gems/3.1.0/bundler/gems/fastlane-729fb915082d/match/lib/match/runner.rb:106:in `block (2 levels) in run'
12:59:12  	from /Users/jenkins/.rbenv/versions/3.1.2/lib/ruby/gems/3.1.0/bundler/gems/fastlane-729fb915082d/match/lib/match/runner.rb:105:in `loop'
12:59:12  	from /Users/jenkins/.rbenv/versions/3.1.2/lib/ruby/gems/3.1.0/bundler/gems/fastlane-729fb915082d/match/lib/match/runner.rb:105:in `block in run'
12:59:12  	from /Users/jenkins/.rbenv/versions/3.1.2/lib/ruby/gems/3.1.0/bundler/gems/fastlane-729fb915082d/match/lib/match/runner.rb:104:in `each'
12:59:12  	from /Users/jenkins/.rbenv/versions/3.1.2/lib/ruby/gems/3.1.0/bundler/gems/fastlane-729fb915082d/match/lib/match/runner.rb:104:in `run'
12:59:12  	from /Users/jenkins/.rbenv/versions/3.1.2/lib/ruby/gems/3.1.0/bundler/gems/fastlane-729fb915082d/fastlane/lib/fastlane/actions/sync_code_signing.rb:19:in `run'
12:59:12  	from /Users/jenkins/.rbenv/versions/3.1.2/lib/ruby/gems/3.1.0/bundler/gems/fastlane-729fb915082d/fastlane/lib/fastlane/runner.rb:263:in `block (2 levels) in execute_action'
12:59:12  	from /Users/jenkins/.rbenv/versions/3.1.2/lib/ruby/gems/3.1.0/bundler/gems/fastlane-729fb915082d/fastlane/lib/fastlane/actions/actions_helper.rb:69:in `execute_action'
12:59:12  	from /Users/jenkins/.rbenv/versions/3.1.2/lib/ruby/gems/3.1.0/bundler/gems/fastlane-729fb915082d/fastlane/lib/fastlane/runner.rb:255:in `block in execute_action'
12:59:12  	from /Users/jenkins/.rbenv/versions/3.1.2/lib/ruby/gems/3.1.0/bundler/gems/fastlane-729fb915082d/fastlane/lib/fastlane/runner.rb:229:in `chdir'
12:59:12  	from /Users/jenkins/.rbenv/versions/3.1.2/lib/ruby/gems/3.1.0/bundler/gems/fastlane-729fb915082d/fastlane/lib/fastlane/runner.rb:229:in `execute_action'
12:59:12  	from /Users/jenkins/.rbenv/versions/3.1.2/lib/ruby/gems/3.1.0/bundler/gems/fastlane-729fb915082d/fastlane/lib/fastlane/runner.rb:157:in `trigger_action_by_name'
12:59:12  	from /Users/jenkins/.rbenv/versions/3.1.2/lib/ruby/gems/3.1.0/bundler/gems/fastlane-729fb915082d/fastlane/lib/fastlane/fast_file.rb:159:in `method_missing'
12:59:12  	from Fastfile:40:in `block (2 levels) in parsing_binding'
12:59:12  	from /Users/jenkins/.rbenv/versions/3.1.2/lib/ruby/gems/3.1.0/bundler/gems/fastlane-729fb915082d/fastlane/lib/fastlane/lane.rb:41:in `call'
12:59:12  	from /Users/jenkins/.rbenv/versions/3.1.2/lib/ruby/gems/3.1.0/bundler/gems/fastlane-729fb915082d/fastlane/lib/fastlane/runner.rb:204:in `try_switch_to_lane'
12:59:12  	from /Users/jenkins/.rbenv/versions/3.1.2/lib/ruby/gems/3.1.0/bundler/gems/fastlane-729fb915082d/fastlane/lib/fastlane/runner.rb:146:in `trigger_action_by_name'
12:59:12  	from /Users/jenkins/.rbenv/versions/3.1.2/lib/ruby/gems/3.1.0/bundler/gems/fastlane-729fb915082d/fastlane/lib/fastlane/fast_file.rb:159:in `method_missing'
12:59:12  	from Fastfile:178:in `block (2 levels) in parsing_binding'
12:59:12  	from /Users/jenkins/.rbenv/versions/3.1.2/lib/ruby/gems/3.1.0/bundler/gems/fastlane-729fb915082d/fastlane/lib/fastlane/lane.rb:41:in `call'
12:59:12  	from /Users/jenkins/.rbenv/versions/3.1.2/lib/ruby/gems/3.1.0/bundler/gems/fastlane-729fb915082d/fastlane/lib/fastlane/runner.rb:49:in `block in execute'
12:59:12  	from /Users/jenkins/.rbenv/versions/3.1.2/lib/ruby/gems/3.1.0/bundler/gems/fastlane-729fb915082d/fastlane/lib/fastlane/runner.rb:45:in `chdir'
12:59:12  	from /Users/jenkins/.rbenv/versions/3.1.2/lib/ruby/gems/3.1.0/bundler/gems/fastlane-729fb915082d/fastlane/lib/fastlane/runner.rb:45:in `execute'
12:59:12  	from /Users/jenkins/.rbenv/versions/3.1.2/lib/ruby/gems/3.1.0/bundler/gems/fastlane-729fb915082d/fastlane/lib/fastlane/lane_manager.rb:46:in `cruise_lane'
12:59:12  	from /Users/jenkins/.rbenv/versions/3.1.2/lib/ruby/gems/3.1.0/bundler/gems/fastlane-729fb915082d/fastlane/lib/fastlane/command_line_handler.rb:34:in `handle'
12:59:12  	from /Users/jenkins/.rbenv/versions/3.1.2/lib/ruby/gems/3.1.0/bundler/gems/fastlane-729fb915082d/fastlane/lib/fastlane/commands_generator.rb:110:in `block (2 levels) in run'
12:59:12  	from /Users/jenkins/.rbenv/versions/3.1.2/lib/ruby/gems/3.1.0/gems/commander-4.6.0/lib/commander/command.rb:187:in `call'
12:59:12  	from /Users/jenkins/.rbenv/versions/3.1.2/lib/ruby/gems/3.1.0/gems/commander-4.6.0/lib/commander/command.rb:157:in `run'
12:59:12  	from /Users/jenkins/.rbenv/versions/3.1.2/lib/ruby/gems/3.1.0/gems/commander-4.6.0/lib/commander/runner.rb:444:in `run_active_command'
12:59:12  	from /Users/jenkins/.rbenv/versions/3.1.2/lib/ruby/gems/3.1.0/bundler/gems/fastlane-729fb915082d/fastlane_core/lib/fastlane_core/ui/fastlane_runner.rb:124:in `run!'
12:59:12  	from /Users/jenkins/.rbenv/versions/3.1.2/lib/ruby/gems/3.1.0/gems/commander-4.6.0/lib/commander/delegates.rb:18:in `run!'
12:59:12  	from /Users/jenkins/.rbenv/versions/3.1.2/lib/ruby/gems/3.1.0/bundler/gems/fastlane-729fb915082d/fastlane/lib/fastlane/commands_generator.rb:354:in `run'
12:59:12  	from /Users/jenkins/.rbenv/versions/3.1.2/lib/ruby/gems/3.1.0/bundler/gems/fastlane-729fb915082d/fastlane/lib/fastlane/commands_generator.rb:43:in `start'
12:59:12  	from /Users/jenkins/.rbenv/versions/3.1.2/lib/ruby/gems/3.1.0/bundler/gems/fastlane-729fb915082d/fastlane/lib/fastlane/cli_tools_distributor.rb:123:in `take_off'
12:59:12  	from /Users/jenkins/.rbenv/versions/3.1.2/lib/ruby/gems/3.1.0/bundler/gems/fastlane-729fb915082d/bin/fastlane:23:in `<top (required)>'
12:59:12  	from /Users/jenkins/.rbenv/versions/3.1.2/lib/ruby/gems/3.1.0/bin/fastlane:25:in `load'
12:59:12  	from /Users/jenkins/.rbenv/versions/3.1.2/lib/ruby/gems/3.1.0/bin/fastlane:25:in `<top (required)>'
12:59:12  	from /Users/jenkins/.rbenv/versions/3.1.2/lib/ruby/gems/3.1.0/gems/bundler-2.4.19/lib/bundler/cli/exec.rb:58:in `load'
12:59:12  	from /Users/jenkins/.rbenv/versions/3.1.2/lib/ruby/gems/3.1.0/gems/bundler-2.4.19/lib/bundler/cli/exec.rb:58:in `kernel_load'
12:59:12  	from /Users/jenkins/.rbenv/versions/3.1.2/lib/ruby/gems/3.1.0/gems/bundler-2.4.19/lib/bundler/cli/exec.rb:23:in `run'
12:59:12  	from /Users/jenkins/.rbenv/versions/3.1.2/lib/ruby/gems/3.1.0/gems/bundler-2.4.19/lib/bundler/cli.rb:492:in `exec'
12:59:12  	from /Users/jenkins/.rbenv/versions/3.1.2/lib/ruby/gems/3.1.0/gems/bundler-2.4.19/lib/bundler/vendor/thor/lib/thor/command.rb:27:in `run'
12:59:12  	from /Users/jenkins/.rbenv/versions/3.1.2/lib/ruby/gems/3.1.0/gems/bundler-2.4.19/lib/bundler/vendor/thor/lib/thor/invocation.rb:127:in `invoke_command'
12:59:12  	from /Users/jenkins/.rbenv/versions/3.1.2/lib/ruby/gems/3.1.0/gems/bundler-2.4.19/lib/bundler/vendor/thor/lib/thor.rb:392:in `dispatch'
12:59:12  	from /Users/jenkins/.rbenv/versions/3.1.2/lib/ruby/gems/3.1.0/gems/bundler-2.4.19/lib/bundler/cli.rb:34:in `dispatch'
12:59:12  	from /Users/jenkins/.rbenv/versions/3.1.2/lib/ruby/gems/3.1.0/gems/bundler-2.4.19/lib/bundler/vendor/thor/lib/thor/base.rb:485:in `start'
12:59:12  	from /Users/jenkins/.rbenv/versions/3.1.2/lib/ruby/gems/3.1.0/gems/bundler-2.4.19/lib/bundler/cli.rb:28:in `start'
12:59:12  	from /Users/jenkins/.rbenv/versions/3.1.2/lib/ruby/gems/3.1.0/gems/bundler-2.4.19/exe/bundle:37:in `block in <top (required)>'
12:59:12  	from /Users/jenkins/.rbenv/versions/3.1.2/lib/ruby/gems/3.1.0/gems/bundler-2.4.19/lib/bundler/friendly_errors.rb:117:in `with_friendly_errors'
12:59:12  	from /Users/jenkins/.rbenv/versions/3.1.2/lib/ruby/gems/3.1.0/gems/bundler-2.4.19/exe/bundle:29:in `<top (required)>'
12:59:12  	from /Users/jenkins/.rbenv/versions/3.1.2/bin/bundle:25:in `load'
12:59:12  	from /Users/jenkins/.rbenv/versions/3.1.2/bin/bundle:25:in `<main>'

@nekrich
Copy link
Contributor Author

nekrich commented Jan 3, 2024

@viktor-savchik-idf , can you please share the options you use to run the match action? I'm interested in all force_* parameters, the readonly flag and profile type. Thanks.

@kirakoki
Copy link

kirakoki commented Jan 3, 2024

Screenshot 2024-01-03 at 14 55 12

We started recieving this error while trying to create apple profile via fastlane 2.218.0

using the command fastlane match appstore --api_key_path match_api_key.json --team_id $TEAM_ID && fastlane ios bootstrap

@viktor-savchik-idf
Copy link

viktor-savchik-idf commented Jan 3, 2024

@viktor-savchik-idf , can you please share the options you use to run the match action? I'm interested in all force_* parameters, the readonly flag and profile type. Thanks.

@nekrich Here is the complete action, the adhoc type also exhibits the same issue.

lane :certificates_dev do
    	api_key = app_store_connect_api_key_creator

        register_devices(devices_file: "./devices.txt", api_key: api_key)
    	
        match(
    	        app_identifier: ["id.one", "id.two", "id.three"],
      		api_key: api_key,
		type: "development",
		force_for_new_devices: true,
		template_name: "ApplePay In-App Provisioning Distribution",
    	)
end

@jankosecki
Copy link

jankosecki commented Jan 3, 2024

Hi,
I've upgrade fastlane today and I'm observing following error when trying to run iOS build:

/opt/homebrew/Cellar/fastlane/2.218.0/libexec/gems/fastlane-2.218.0/match/lib/match/profile_includes.rb:56:in `devices_differ?': [!] undefined method `map' for nil:NilClass (NoMethodError)

      profile_device_ids = profile_devices.map(&:id).sort
                                          ^^^^
	from /opt/homebrew/Cellar/fastlane/2.218.0/libexec/gems/fastlane-2.218.0/match/lib/match/profile_includes.rb:23:in `should_force_include_all_devices?'
	from /opt/homebrew/Cellar/fastlane/2.218.0/libexec/gems/fastlane-2.218.0/match/lib/match/runner.rb:253:in `fetch_provisioning_profile'
	from /opt/homebrew/Cellar/fastlane/2.218.0/libexec/gems/fastlane-2.218.0/match/lib/match/runner.rb:106:in `block (2 levels) in run'
	from /opt/homebrew/Cellar/fastlane/2.218.0/libexec/gems/fastlane-2.218.0/match/lib/match/runner.rb:105:in `loop'
	from /opt/homebrew/Cellar/fastlane/2.218.0/libexec/gems/fastlane-2.218.0/match/lib/match/runner.rb:105:in `block in run'
	from /opt/homebrew/Cellar/fastlane/2.218.0/libexec/gems/fastlane-2.218.0/match/lib/match/runner.rb:104:in `each'
	from /opt/homebrew/Cellar/fastlane/2.218.0/libexec/gems/fastlane-2.218.0/match/lib/match/runner.rb:104:in `run'
	from /opt/homebrew/Cellar/fastlane/2.218.0/libexec/gems/fastlane-2.218.0/fastlane/lib/fastlane/actions/sync_code_signing.rb:19:in `run'

Triggered by following action:

 match(
      app_identifier: app_id,
      type: options[:profile_type], # adhoc
      readonly: false,
      verbose: false,
      force_for_new_devices: true,
)

EDIT:
I've downgraded fastlane to 2.217.0 and can run my lane without issues so the issue is likely introduces by this change

@thanhcuong1990
Copy link

@viktor-savchik-idf , @thanhcuong1990 can you please check if the fix works nekrich:fix/sigh-cache-parameters-validation?

Gemfile: gem 'fastlane', :git => 'https://github.com/nekrich/fastlane.git', :branch => 'fix/sigh-cache-parameters-validation')?

@nekrich Confirmed, it works for me.

@stherold
Copy link

stherold commented Jan 4, 2024

Wow! I tried that right now with version 2.219.0 and for our 60+ apps this is a pure gamechanger 🎉 Thank you so much for this update 👍

Here are our benchmarks:

matrix-codesigning.sh is the script which runs fastlane match for development/appstore for each of our 60+ apps. do_refresh actually was a pain in the past with 2h. Now that this is running only in 7 minutes for 120 fastlane match executions this is amazing 🤯

#### Before

matrix-codesigning.sh             : 34s
matrix-codesigning.sh "do_refresh": 2h 9m

#### After

matrix-codesigning.sh             : 30s
matrix-codesigning.sh "do_refresh": 7m

SubhrajyotiSen pushed a commit to KeepTruckin/fastlane that referenced this pull request Jan 17, 2024
…to 100x (fastlane#21694)

* [match] increase match speed with caching

* chore: skip new profile validation

* chore: don’t install a nonexistent profile

* chore: code readability improvements

* chore: improve cert & device difference

* chore: fix variable naming

* chore: remove redundant var init

* chore: check for unique profiles

* fix: typo

* chore: match portal bundle id fetcher expect only arrays

* fix: only uuids with one hyphen supported for silicon macs

* chore: add comment about cert type downcasing

Co-authored-by: Roger Oba <rogerluan.oba@gmail.com>

* chore: use standard syntax for multiline blocks

* chore: remove empty it

* chore: update cache returns

* chore: extra check for cached certs after reset

---------

Co-authored-by: Roger Oba <rogerluan.oba@gmail.com>
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment
Projects
None yet
Development

Successfully merging this pull request may close these issues.

None yet

9 participants