Skip to content

Conversation

@nightnei
Copy link
Contributor

@nightnei nightnei commented Feb 14, 2025

Related issues

Proposed Changes

If we create a new site with the help of backup archive, then it works under the hood as - we create a new website and then import backup to created website. During importing, we need to replace website URL with local URL (e.g. localhost:8001), but we set up port only during running a website, so it ends up with localhost:undefined.
With proposed changes in this PR we are chisong port for website during creation of it, instead of during first running.

Testing Instructions

Apply the next diff:

diff --git a/src/lib/import-export/import/importers/importer.ts b/src/lib/import-export/import/importers/importer.ts
index b82ec5d..f7a0ff0 100644
--- a/src/lib/import-export/import/importers/importer.ts
+++ b/src/lib/import-export/import/importers/importer.ts
@@ -102,6 +102,7 @@ abstract class BaseImporter extends EventEmitter implements Importer {
                const oldUrlVariants = [ `http://${ urlWithoutProtocol }`, `https://${ urlWithoutProtocol }` ];
 
                for ( const urlToReplace of oldUrlVariants ) {
+                       console.info( `Replacing URL: ${ urlToReplace } -> ${ studioUrl }` );
                        const { stderr, exitCode } = await server.executeWpCliCommand(
                                `search-replace '${ urlToReplace }' '${ studioUrl }'`,
                                { skipPluginsAndThemes: true }

  1. Open Studio
  2. Create a new website with teh help of backup
  3. Assert that in terminal logs (from the diff above) you see a correct port, instead of undefined

}
}

const port = await portFinder.getOpenPort();
Copy link
Contributor Author

@nightnei nightnei Feb 14, 2025

Choose a reason for hiding this comment

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

We are running website immidiatelly after creating it, so it's tiotale safe to define the port during setting up website. And I would say, there are even benefit of such approach, since we configure everything for our site in advance and have complete data for it and I don't see any benefit in postponning choosing port for it.

Copy link
Member

@sejas sejas Feb 18, 2025

Choose a reason for hiding this comment

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

Now that the port is assigned in site creation, should we remove tha code from SiteServer.start ?

const port = await portFinder.getOpenPort( this.details.port );
portFinder.addUnavailablePort( this.details.port );

Maybe we can also remove the code related to release port:

portFinder.releasePort( this.details.port );

Copy link
Contributor Author

@nightnei nightnei Feb 18, 2025

Choose a reason for hiding this comment

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

I was thinking about it, but:

  1. What in 1 months the users starts their website again, but another tool uses already this port too. Then in this case, portFinder.getOpenPort( this.details.port ); fixes the issue and will pick up the next available port. I thought that it way intentionally added. If not intentionally, then anyway we should keep it to cover such case :)
  2. Actually, reading the code, I have assumption that we have another bug, connected to the point above. And it's edge case, but I was going to emulate case from the previous point and check how Studio handles it, since I think that we should do some thing like replacUrl in DB if port is busy during starting site and if await portFinder.getOpenPort( this.details.port ); selected another one port. So in this case we need to update DB and update appdata-v1.json (but this point is already hanled inside start function, so we need to updater just DB).

But this my assumption is connected, but another topic, so in this PR I want to fix described issues and later cover that edge case as a separate PR, to not mix up everything.

WDYT about my thoughts?

Copy link
Contributor Author

Choose a reason for hiding this comment

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

@sejas btw, I have also assumption that this issue is related to what I am mentioning above.

I will investigate it, but off the top of my head, the issue here is:

  1. We created website and set some port for urls inside DB
  2. Then we removed site and created a new one with the same DB
  3. As a result, data in the DB has old port, but we assigned a new one in appdata-v1.json during creating a site

What I want to say is - maybe, during starting server, we should always take port from const port = await portFinder.getOpenPort( this.details.port ); and make updated to DB? So that, I suppose, we will fix this issue and also we will fix edge case mentioned by me in the previous message.

Thinking about it more, I believe that we should do complex fix, like I proposed above or something similar, to keep Studio more stable.

Copy link
Member

@sejas sejas Feb 18, 2025

Choose a reason for hiding this comment

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

My concern is that in this PR we are adding another portFinder.getOpenPort call and now we are setting the port to the studio site in two places, and it's not clear to me which one actually is setting the final port. That's why I was suggesting to address it in this PR.

I understand the concern about a port being already busy, but currently the WordPress site will redirect to that port producing an unexpected behaviour. So I don't see harm on removing that code.

We could create an issue to consider that edge case and "replacing" the url+port in the database and appdata. We don't need to try to fix that in this PR. Maybe the issue is an edge case that it's not worth implementing it and we could document it somewhere, or wait to see if any user reports it. There are other solutions, like displaying an alert if the port is busy.

Copy link
Contributor Author

Choose a reason for hiding this comment

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

I see, ok, let's go this way. I will create issues and I removed this:

const port = await portFinder.getOpenPort( this.details.port ); 
portFinder.addUnavailablePort( this.details.port ); 

But I think it's nice to keep portFinder.releasePort( this.details.port );, however it's not critical. The reason is - if we remove a site (e.g. :8002) and creating a new site, then willt be created 8003, instead of 8002 (which is actually free, and there is no sense to skip it).
WDYT, should we remove releasePort? I don't have strong preference, both options are ok - I like removing code but also I like when ports are used sequentially instead of jumping, so there are pros/cons in both cases :)

Copy link
Contributor Author

@nightnei nightnei Feb 18, 2025

Choose a reason for hiding this comment

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

I checked my assumption and it indeed fails and we don't show any error in UI, just endless "Starting..." copy.
Created an issue.

Copy link
Member

Choose a reason for hiding this comment

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

But I think it's nice to keep portFinder.releasePort( this.details.port );, however it's not critical. The reason is - if we remove a site (e.g. :8002) and creating a new site, then willt be created 8003, instead of 8002 (which is actually free, and there is no sense to skip it).
WDYT, should we remove releasePort? I don't have strong preference, both options are ok - I like removing code but also I like when ports are used sequentially instead of jumping, so there are pros/cons in both cases :)

I didn't see the code or tested this case but I also think the port assignment should be sequential. Maybe we should release the port when the site is removed ? I thought that if it's not in appData then it could be free to use.

Copy link
Member

Choose a reason for hiding this comment

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

Ok!, It seems the releaseport is already in delete and not in stop as I thought. It's good to leave it 👌

portFinder.releasePort( this.details.port );

} );
clearImportState( newSite.id );
}
await startServer( newSite.id );
Copy link
Contributor Author

@nightnei nightnei Feb 17, 2025

Choose a reason for hiding this comment

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

@nightnei nightnei linked an issue Feb 17, 2025 that may be closed by this pull request
@nightnei nightnei marked this pull request as ready for review February 17, 2025 17:23
Copy link
Contributor

@wojtekn wojtekn left a comment

Choose a reason for hiding this comment

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

Works as expected.

id: tempSiteId,
name: siteName || path,
path,
port: 9999, // Set a temporary port
Copy link
Contributor

Choose a reason for hiding this comment

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

Why we need to set temporary port?

Copy link
Member

Choose a reason for hiding this comment

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

It's used as a placeholder to comply with the types.
This site placeholder is added so that Studio can display the new site in the sidebar while it's being created. The site information will be replaced once the site is created when the call to const data = await getIpcApi().createSite(path, siteName); resolves.

We could split getIpcApi().createSite into two functions: one that retrieves the siteId and new port, add the site to the state in the react, and then pass those variables as parameters to the createSite function.

If we decide to use the temporary port, we could use a more different port like -1 that could help us discover any issues during site creation.

Copy link
Contributor Author

Choose a reason for hiding this comment

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

@sejas Updated to -1, makes sense, good idea 👍

@wojtekn wojtekn requested a review from a team February 18, 2025 08:53
Copy link
Member

@sejas sejas left a comment

Choose a reason for hiding this comment

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

Looks great. I confirm I was able to import a new studio site from a backup and the site started correctly with a new port following the next sequence.

I left a comment suggesting to remove the portFinder code from the start and stop functions.

My reasoning is that now that we don't override the WordPress siteurl, if we start a site in a port different to what's saved in sitedetails, then it will redirect to that URL producing unexpected behaviours.

id: tempSiteId,
name: siteName || path,
path,
port: 9999, // Set a temporary port
Copy link
Member

Choose a reason for hiding this comment

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

It's used as a placeholder to comply with the types.
This site placeholder is added so that Studio can display the new site in the sidebar while it's being created. The site information will be replaced once the site is created when the call to const data = await getIpcApi().createSite(path, siteName); resolves.

We could split getIpcApi().createSite into two functions: one that retrieves the siteId and new port, add the site to the state in the react, and then pass those variables as parameters to the createSite function.

If we decide to use the temporary port, we could use a more different port like -1 that could help us discover any issues during site creation.

}
}

const port = await portFinder.getOpenPort();
Copy link
Member

@sejas sejas Feb 18, 2025

Choose a reason for hiding this comment

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

Now that the port is assigned in site creation, should we remove tha code from SiteServer.start ?

const port = await portFinder.getOpenPort( this.details.port );
portFinder.addUnavailablePort( this.details.port );

Maybe we can also remove the code related to release port:

portFinder.releasePort( this.details.port );

Copy link
Member

@sejas sejas left a comment

Choose a reason for hiding this comment

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

Thanks for the changes! I tested it and worked as expected 👍
Thanks for creating the other issue.

@nightnei nightnei merged commit abd53d2 into trunk Feb 19, 2025
7 checks passed
@nightnei nightnei deleted the fix/portRaplacementOnCreatingNewSiteFromBackup branch February 19, 2025 12:07
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

None yet

Projects

None yet

Development

Successfully merging this pull request may close these issues.

Search and replace doesn't work correctly during the import

4 participants